引入
this
調(diào)用一個成員函數(shù),編譯器用請求該函數(shù)的對象地址初始化this,所以this的目的總是指向這個對象,因此this是一個常量指針。引入
const成員函數(shù)
以下是Sales_data類的一個成員函數(shù)的定義,參數(shù)列表之后的const作用是修改隱式this指針的類型,因為默認情況下,this的類型是指向類類型非常量版本的常量指針。所以默認情況不能把this綁定到一個常量對象上。這樣使用const的成員函數(shù)被稱為常量成員函數(shù)。
std::string isbn() const {return bookNo;}
類作用域
編譯器首先編譯成員的聲明,然后是成員函數(shù)體,所以成員函數(shù)體可以隨意使用類中的其他成員無須在意成員的順序。定義一個返回
this對象的函數(shù)
函數(shù)類似于某個內(nèi)置運算符時,應(yīng)該令該函數(shù)的行為盡量模仿這個運算符。內(nèi)置賦值運算符把它的左側(cè)運算對當左值返回,意味著這些函數(shù)返回的是對象本身而非對象的副本,因此combine必須返回引用類型。
Sales_data& Sales_data::combine(const Sales_data &rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this; //解引用指針獲取執(zhí)行該函數(shù)的對象。
}
- 類相關(guān)的非成員函數(shù)
如果函數(shù)在概念上屬于類但是不定義在類中,則它一般應(yīng)與類聲明在同一個頭文件。
默認情況下拷貝類的對象,拷貝的是對象的數(shù)據(jù)成員。
- 構(gòu)造函數(shù)
構(gòu)造函數(shù)不能聲明為const,直到構(gòu)造函數(shù)完成初始化過程,對象才能取得"常量"屬性。因此,構(gòu)造函數(shù)在const對象的構(gòu)造過程中可以向其寫值。合成的默認構(gòu)造函數(shù):類沒有顯示的定義構(gòu)造函數(shù),那么編譯器會為我們隱式地定義一個合成的默認構(gòu)造函數(shù),安照類內(nèi)初始值初始化成員,沒有的話則默認初始化成員。只有當類沒有聲明任何構(gòu)造函數(shù)的時候,才會默認構(gòu)造函數(shù)。使用
= default要求編譯器生成構(gòu)造函數(shù)。構(gòu)造函數(shù)初始值列表:
Sales_data = (const std::string &s, unsigned n, double p): bookNo(s), units_sold(n), revenue(p*n) {}
- 一個
const成員函數(shù)如果以引用的形式返回*this指針,那么它的返回類型將是常量引用。
基于const的重載
如下,當一個成員調(diào)用另一個成員的時候,this指針在其中隱式地傳遞,當display的非常量版本調(diào)用do_display的時候,它的this指針隱式地從指向非常量的指針轉(zhuǎn)換成指向常量的指針。
#include <iostream>
#include <string>
using namespace std;
class Screen{
public:
typedef std::string::size_type pos;
Screen() = default; // 因為要寫另一個構(gòu)造函數(shù)
Screen(pos ht, pos wd, char c): height(ht), width(wd), contents(ht* wd, c) {}
char get() const
{return contents[cursor];} // 類內(nèi)部聲明定義的隱式內(nèi)聯(lián)函數(shù)
inline char get(pos ht, pos wd) const; // 顯示內(nèi)聯(lián)
Screen &set(char);
SCreen &set(pos, pos, char);
Screen &move(pos r, pos c); //能在之后被設(shè)為內(nèi)聯(lián)函數(shù)
Screen &display(std::ostream &os)
{do_display(os); return *this;}
const Screen &display(std::ostream &os) const
{do_display(os); return *this;}
private:
pos cursor = 0; //光標的意思
pos height = 0, width = 0;
std::string contents;
void do_display(std::ostream &os) const{os << contents;}
};
inline // 在函數(shù)的定義處指定為內(nèi)聯(lián)函數(shù)
Screen &Screen::move(pos r, pos c)
{
pos row = r * width;
cursor = row + c;
return *this; //左值
}
char Screen::get(pos r, pos c) const
{
pos row = r * width;
return contents[row + c];
}
inline
Screen &Screen::set(char c)
{
contents[cursor] = c;
return *this;
}
inline
Screen &Screen::set(pos r, pos col, char ch)
{
contents[r*width +col] =ch;
return *this;
}
int main() {
Screen myscreen(5, 5, 'F');
char ch =myscreen.get();
ch = myscreen.get(0, 0);
cout << ch << endl;
}
注:轉(zhuǎn)換成常量:指向T類型的指針或引用分別轉(zhuǎn)換成指向const T的指針或引用:
int i ;
const int & j = i; //非常量轉(zhuǎn)換成const int 的引用
const int *p = &i; //非常量的地址轉(zhuǎn)換成const的地址
- 類的聲明
class Screen; // Screen類的聲明
前項聲明(是一種不完全類型)的使用:可以定義指向這種類型的指針或者引用,聲明(但不能定義)以不完全類型作為參數(shù)或者返回類型的函數(shù)。
必須完成類的定義,編譯器才能知道存儲數(shù)據(jù)成員需要多少空間。因為只有當類全部完成后才算被定義,因此不能有一個類的成員類型是該類自己。
但是類的名字出現(xiàn)后,聲明了該類,因此類允許包含自身類型的引用或者指針:
class Link_Screen{
Screen window;
Link_Screen *next;
Link_Screen *prev;
}
友元函數(shù)
一個類指定了友元類,則友元類的成員函數(shù)可以訪問此類的所有成員。類的作用域
構(gòu)造函數(shù)再談
構(gòu)造函數(shù)初始值列表的必要性:如果成員是const、引用,或者屬于某種未提供默認構(gòu)造函數(shù)的類類型,必須通過構(gòu)造函數(shù)初始值列表為這些成員提供初值。
class ConstRef{
public:
ConstRef(int ii);
private:
int i;
const int c;
int &ri;
}
ConstRef::ConstRef(int ii)
{
i = ii; //正確
c = ii; //錯誤 :不能給const復(fù)制
ri = i; //錯誤 :ri沒被初始化
}
那么成員初始化的順序是:與他們在類中的定義一致。
默認實參與構(gòu)造函數(shù):可以重寫一個使用默認實參的構(gòu)造函數(shù)
class Sales_data{
public:
//定義默認構(gòu)造函數(shù),接受一個字符串初始值
Sales_data(std::string s = " ") bookNo(s) {}
private:
....
}
- 委托構(gòu)造函數(shù):delegating constructor,委托構(gòu)造函數(shù)就是把自己的初始化全部交給其他構(gòu)造函數(shù),受委托的構(gòu)造函數(shù)初始值列表和函數(shù)體執(zhí)行后才輪到委托構(gòu)造函數(shù)。
- 類的靜態(tài)成員:與類直接相關(guān)的成員,不包含
this指針,靜態(tài)成員函數(shù)不能聲明為const的,不能再static函數(shù)體內(nèi)使用this指針。
class Account{
public:
void calculate() {amount += amount * interestRate;}
static double rate() {return interestRate;}
static void rate(double);
private:
std::string owner;
double amount;
static constexpr int period = 30; //period是常量表達式
static double interestRate;
static double initRate();
}
// static關(guān)鍵字出現(xiàn)在類內(nèi)部
void Account::rate(double newRate)
{
interestRate = newRate;
}
由上看出,必須在內(nèi)外初始化每個靜態(tài)成員。
類內(nèi)初始化必須要求靜態(tài)成員是字面值常量類型的constexpr。
- 靜態(tài)成員與普通成員的不同:
- 靜態(tài)數(shù)據(jù)成員的類型可以就是她所屬的類類型;
2.可使用靜態(tài)成員做默認實參;
class Account{
public:
void calculate() {amount += amount * interestRate;}
static double rate() {return interestRate;}
static void rate(double);
private:
std::string owner;
double amount;
static double interestRate;
static double initRate();
}
void Account::rate(double newRate)
{
interestRate = newRate;
}