C++學習筆記(6)
面向物件程式設計: 1.物件和類
(1)宣告類: 類定義了物件的屬性和行為。
一個物件的狀態: 用資料域以及他們的當前值來表示。
一個物件的行為,由一組函式確定。
所以在c++類中,用變數定義資料域,用函式來定義行為
(2)定義類和建立物件: 定義一個圓的類:
#include <iostream> using namespace std; class Circle { public: double radius; // constructor Circle() { radius = 1.0; } // 構造方法 Circle(double new_radius) { radius = new_radius; } // 函式 double getArea() { return 3.14 * radius * radius; } }; // 這裡要寫分號 int main(int argc, char *argv[]) { Circle circle1; Circle circle2(12.5); Circle circle3(123); cout << "radius of circle 1 is " << circle1.radius << endl; cout << "Area of circle 3 is " << circle3.getArea() << endl; return 0; }
public關鍵字:表示所有的資料域,建構函式和普通成員函式都可以通過類物件來訪問。如果不用關鍵字public,那麼這些成員的可見性預設為private
瞭解UML圖(Unified Modelling Language)統一建模語言描述
簡單程式:定義一個電視TV的類,包括頻道切換,開關機,音量調節
#include <iostream> using namespace std; class TV { public: int channel; int volume_level; bool on; //定義構造方法 TV() { channel = 1; volume_level = 40; on = false; } void turnOn() { on = true; } void turnOff() { on = false; } void setChannel(int new_channel) { if(on && new_channel >=1 && new_channel<=120) { channel = new_channel; } } void setVolume(int volume) { if(on && volume>=0 && volume<=100) { volume_level = volume; } } void channelUp() { if(on && channel<120) channel++; } void channelDowm() { if(on && channel>0) channel--; } void volumeUp() { if(on && volume_level<100) volume_level++; } void volumeDown() { if(on && volume_level>0) volume_level--; } }; int main(int argc, char *argv[]) { TV tv1; cout << "The state of tv is " << tv1.on << endl; cout << "The channel is " << tv1.channel << endl; cout << "The volume is " << tv1.volume_level << endl; tv1.turnOn(); tv1.setChannel(56); tv1.setVolume(60); cout << "The state of tv is " << tv1.on << endl; cout << "The channel is " << tv1.channel << endl; cout << "The volume is " << tv1.volume_level << endl; tv1.channelUp(); tv1.volumeDown(); cout << "The state of tv is " << tv1.on << endl; cout << "The channel is " << tv1.channel << endl; cout << "The volume is " << tv1.volume_level << endl; return 0; }
2.建構函式
建構函式可以理解為一種特殊的函式,與普通的函式相比,主要不同點有:
1.建構函式的名字必須與類的名字相同
2.建構函式沒有返回型別 返回void也不可以
3.建立物件時,建構函式被呼叫, 他的作用就是初始化物件
建構函式也可以過載(可以同名,但函式簽名不同),建構函式用來初始化資料域。
注: 類中的變數作為類的新成員,在宣告時不能進行初始化。比如Circle類裡面的radius,在宣告不能初始化,只能在構造方法中為其賦值。
3.建立及使用物件
物件建立後,可以通過.運算(即物件成員訪問運算子)來訪問物件的資料以及呼叫物件的函式
儘量將類名的每個單詞首字母大寫
“=”可以進行兩個物件之間內容的複製,但他們仍然是兩個不同的物件
@@,一個物件包含的資料儲存在記憶體裡,但是函式並不需要儲存,因為函式是這個類所有物件共享的,編譯器僅僅建立一份拷貝就可以了。例如對於circle1, circle2,他們的大小都是一個double型別所佔的位元組的大小。
@@有時建立一個物件,但只需要使用一次,這時無需為物件命名,建立為匿名物件即可
3.類定義和類實現的分離
分離類定義和類實現有利於類的維護。
使用類的程式稱為客戶程式。
::稱為二元作用域解析運算子,指明類成員的作用範圍。
分離的好處:
1.可以實現隱藏。在不改變類的定義的前提下,可以自由修改類的實現
2.作為軟體供應商,只要提供類定義的檔案和類實現的目的碼,從而隱藏了類實現的原始碼,保護軟體上的知識產產權
類定義放在h檔案中,類實現在.cpp檔案中
.h檔案中類的定義
// 關於類的定義
class Circle
{
public:
// 定義資料域
double radius;
// 構建函式
Circle();
// 構建函式
Circle(double);
// 定義函式
double getArea();
}
.cpp檔案中類的實現
#include "E:\back_up\code\c_plus_code\chapter10\external_file\circle.h"
Circle::Circle()
{
radius = 1.0;
}
Circle::Circle(double new_radius)
{
radius = new_radius;
}
double Circle::getArea()
{
return 3.14*radius*radius;
}
在main.cpp中呼叫:
#include <iostream>
#include "E:\back_up\code\c_plus_code\chapter10\external_file\circle.h"
using namespace std;
int main(int argc, char *argv[])
{
Circle c1;
Circle c2(5);
cout << "The radius of c1 is " << c1.radius << endl;
cout << "The area of c1 is " << c1.getArea() << endl;
cout << "The radius of c2 is " << c2.radius << endl;
cout << "The area of c2 is " << c2.getArea() << endl;
return 0;
}
注: include 應該包含circle.h的完整路徑,否則會報錯
4.避免多次包含
Head.h檔案
#include circle.h
Test.cpp檔案:
#include circle.h
#include head.h
在上面的程式碼中,circle.h被重複包含,編譯器會報錯
如何解決在一個程式中多次包含相同的標頭檔案。如果多次包含,C++編譯器會報錯,因為前處理器會把#include後的內容直接插入到他們被包含的位置,如果重複包含,就相當於重複插入了相同的內容,就會出現類有多個定義的報錯。
包含保護: 原語句 #ifndef和#define可以避免標頭檔案多次被包含,所以在標頭檔案中應該包含。
// 關於類的定義
#ifndef CIRCLE_H
#define CIRCLE_H
class Circle
{
public:
// 定義資料域
double radius;
// 構建函式
Circle();
// 構建函式
Circle(double);
// 定義函式
double getArea();
} ;
#endif
先測試CIRCLE_H是否已經定義,如果沒有,則定義,並且把標頭檔案的其他部分也包含進來,否則跳過、
5. 資料域封裝
資料域私有可以保護資料,使類便於維護。
例如,對於類Circle,要防止客戶程式直接修改radius的值,以防止客戶程式直接修改類的屬性,因此,使用關鍵字private,將資料域設為私有,這就是資料域封裝。
一個私有的程式,無法通過直接引用類物件來訪問它。 如果需要訪問,需改,需要定義一個get()函式和一個set()函式,即訪問器(accessor)和更改器(mutator)
Circle類:
circle.h檔案
// 關於類的定義
#ifndef CIRCLE_H
#define CIRCLE_H
class Circle
{
private: // 資料域封裝
double radius;
public:
// 定義資料域
//double radius;
// 構建函式
Circle();
// 構建函式
Circle(double);
// 定義函式
double getArea();
// define accessor
double getRadius();
// define mutator
void setRadius(double);
} ;
#endif
circle.cpp檔案
// 類的實現
#include "E:\back_up\code\c_plus_code\chapter10\external_file\circle.h"
Circle::Circle()
{
radius = 1.0;
}
Circle::Circle(double new_radius)
{
radius = new_radius;
}
double Circle::getArea()
{
return 3.14*radius*radius;
}
double Circle::getRadius() // 訪問器
{
return radius;
}
void Circle::setRadius(double new_radius) // 更改器
{
radius = (new_radius>=0) ? new_radius : 0; //語法糖
}
客戶端程式:
#include <iostream>
#include "E:\back_up\code\c_plus_code\chapter10\external_file\circle.h"
using namespace std;
int main(int argc, char *argv[])
{
//Circle c1;
Circle c2(5);
cout << "The radius of c2 is " << c2.getRadius() << endl;
cout << "The area of c2 is " << c2.getArea() << endl;
c2.setRadius(10.5);
cout << "The radius of c2 is " << c2.getRadius() << endl;
cout << "The area of c2 is " << c2.getArea() << endl;
return 0;
}
6.變數作用域
全域性變數
區域性變數
區域性靜態變數
在類中,資料域被定義為便變數的形式,可以被所有成員函式訪問
在類中,如果一個區域性變數和一個數據域有相同的名字,資料域將被覆蓋,區域性變數的優先順序是最高的
7.類的抽象和封裝
銀行獲取貸款的例子:
Loan:
資料域: 利率, 貸款額度, 貸款年限 (用private實現類的封裝)
構造方法: Loan()以及Loan(int, double , double)
函式:
year(access, mutator),
loan_amount(access, mutator)
interest_rate(access, mutator)
getMonthlyPayment()
getTotalPayment()
程式碼:
Loan.h檔案:
// loan的定義
#ifndef LOAN_H
#define LOAN_H
class Loan
{
public:
// 構造方法
Loan();
Loan(int year, double loan_amount, double year_interest_rate);
int getYear(); // accessor for year
void setYear(int); // mutator for year
double getYearInterestRate(); // accessor for interest rate
void setYearInterestRate(double); // mutator for interest rate
double getLoanAmount(); // access for LoanAmount
void setLoanAmount(double); //mutator for
double getMonthPayment();
double getTotalPayment();
private:
int years;
double loan_amounmt;
double year_interest_rate;
//double month_payment;
//double total_payment;
};
#endif
Loan.cpp檔案:
// 類的實現
#include "E:\back_up\code\c_plus_code\chapter10\external_file\loan.h"
#include <cmath>
Loan::Loan()
{
years = 5;
loan_amounmt = 100000;
year_interest_rate = 4;
}
Loan::Loan(int year, double amounmt, double rate) // 在類的實現中,引數的名字不能與變數的名字相同
{
years = year;
loan_amounmt = amounmt;
year_interest_rate = rate;
}
int Loan::getYear()
{
return years;
}
void Loan::setYear(int year)
{
years = year;
}
double Loan::getYearInterestRate()
{
return year_interest_rate;
}
void Loan::setYearInterestRate(double rate)
{
year_interest_rate = rate;
}
double Loan::getLoanAmount()
{
return loan_amounmt;
}
void Loan::setLoanAmount(double amounmt)
{
loan_amounmt = amounmt;
}
double Loan::getMonthPayment()
{
double month_interest_rate = year_interest_rate / 1200;
return loan_amounmt * month_interest_rate / (1 - pow(1 / (1+month_interest_rate), years * 12));
}
double Loan::getTotalPayment()
{
return getMonthPayment() * 12 * years;
}
注:在類的實現中函式引數的命名與類中的資料域命名應該不一樣,否則會有錯誤(程式不報錯,但會出現錯誤的結果)
使用者程式:
#include <iostream>
#include "E:\back_up\code\c_plus_code\chapter10\external_file\circle.h"
#include "E:\back_up\code\c_plus_code\chapter10\external_file\loan.h"
using namespace std;
int main(int argc, char *argv[])
{
Loan loan_1;
cout << "The year is " << loan_1.getYear() << endl;
cout << "loan amount is " << loan_1.getLoanAmount() << endl;
cout << "loan rate is " << loan_1.getYearInterestRate() << endl;
cout << "month payment is " << loan_1.getMonthPayment() << endl;
cout << "total payment is " << loan_1.getTotalPayment() << endl;
loan_1.setYear(10);
loan_1.setYearInterestRate(8.5);
loan_1.setLoanAmount(80000);
cout << "-----------------------------" << endl;
cout << "The year is " << loan_1.getYear() << endl;
cout << "loan amount is " << loan_1.getLoanAmount() << endl;
cout << "loan rate is " << loan_1.getYearInterestRate() << endl;
cout << "month payment is " << loan_1.getMonthPayment() << endl;
cout << "total payment is " << loan_1.getTotalPayment() << endl;
Loan loan_2(15, 30000, 6.4);
cout << "-----------------------------" << endl;
cout << "The year is " << loan_2.getYear() << endl;
cout << "loan amount is " << loan_2.getLoanAmount() << endl;
cout << "loan rate is " << loan_2.getYearInterestRate() << endl;
cout << "month payment is " << loan_2.getMonthPayment() << endl;
cout << "total payment is " << loan_2.getTotalPayment() << endl;
return 0;
}