C++ primer類(lèi)的基礎(chǔ)精講
定義抽象數(shù)據(jù)類(lèi)型
初探this和
struct Sales_data
{
string isbn(){return bookNo;}
Sales_data & combine(const Sales_data&);
double avg_price() const;
string bookNo;
unsigned units_sold=0;
double revenue=0;
};
Sales_data total;引入this
對(duì)于isbn成員函數(shù)的調(diào)用: total.isbn();
當(dāng)我們調(diào)用成員函數(shù)時(shí),實(shí)則上是在替某個(gè)對(duì)象調(diào)用它。在上面的調(diào)用中,當(dāng)isbn返回bookNo時(shí),實(shí)際上隱式地返回total.bookNo.
成員函數(shù)通過(guò)一個(gè)名為this的額外隱式參數(shù)來(lái)訪(fǎng)問(wèn)調(diào)用它的那個(gè)對(duì)象。當(dāng)我們調(diào)用一個(gè)成員函數(shù)時(shí),用請(qǐng)求該函數(shù)的對(duì)象地址初始化this。例如,如果調(diào)用total.isbn(),編譯器負(fù)責(zé)把total的地址傳遞給isbn的隱式形參this,可以等價(jià)認(rèn)為編譯器將該調(diào)用重寫(xiě)成Sales_data::isbn(&total),調(diào)用Sales_data時(shí)的isbn成員時(shí)傳入了total的地址。
在成員函數(shù)內(nèi)部,我們可以直接使用調(diào)用該函數(shù)的對(duì)象的成員,而無(wú)須通過(guò)成員訪(fǎng)問(wèn)運(yùn)算符來(lái)做到這一點(diǎn),因?yàn)閠his所指的正是這個(gè)對(duì)象。任何對(duì)類(lèi)成員的直接訪(fǎng)問(wèn)都被看做this的隱式調(diào)用,例如,isbn在使用bookNo時(shí),隱式地使用this指向的成員,就如同this->bookNo一樣。
構(gòu)造函數(shù)
定義:類(lèi)通過(guò)一個(gè)或幾個(gè)特殊的成員函數(shù)來(lái)控制其對(duì)象的初始化,這些函數(shù)叫做構(gòu)造函數(shù)。
無(wú)論何時(shí),只要類(lèi)的對(duì)象被創(chuàng)建,就會(huì)執(zhí)行構(gòu)造函數(shù)。
構(gòu)造函數(shù)的名字和類(lèi)名一樣,構(gòu)造函數(shù)沒(méi)有返回類(lèi)型,一個(gè)類(lèi)可以擁有多個(gè)構(gòu)造函數(shù),但每個(gè)構(gòu)造函數(shù)之間必須在參數(shù)數(shù)量或參數(shù)類(lèi)型上存在不同。且構(gòu)造函數(shù)不能被聲明成const。
當(dāng)一個(gè)類(lèi)沒(méi)有定義任何構(gòu)造函數(shù)時(shí),編譯器會(huì)給類(lèi)自動(dòng)添加一個(gè)默認(rèn)構(gòu)造函數(shù),該構(gòu)造函數(shù)無(wú)須任何實(shí)參對(duì)對(duì)象進(jìn)行初始化。
對(duì)前面的Sales_data類(lèi)進(jìn)行編寫(xiě)構(gòu)造函數(shù)
struct Sales_data
{
Sales_data()=default;
Sales_data(const string &s):bookNo(s)()
Sales_data(const string &s,unsigned n,double p):bookNo(s),units_sold(n),revenue(p*n){}
Sales_data(istream &)
string isbn() const{return bookNo;}
Sales_data &combine(const Sales_data&);
double avg_price() const;
string bookNo;
unsigned units_sold=0;
double revenue=0.0;
}(1)=default的含義
如果需要默認(rèn)構(gòu)造函數(shù)起作用,那么可以在參數(shù)列表后面寫(xiě)上=default來(lái)要求編譯器生成默認(rèn)構(gòu)造函數(shù)。
(2)構(gòu)造函數(shù)初始值列表
Sales_data(const string &s):bookNo(s)()
Sales_data(const string &s,unsigned n,double p):bookNo(s),units_sold(n),revenue(p*n){}
上面出現(xiàn)了兩個(gè)新的構(gòu)造函數(shù)的寫(xiě)法,該部分稱(chēng)為構(gòu)造函數(shù)初始值列表。
負(fù)責(zé)為新創(chuàng)建的對(duì)象的一個(gè)或幾個(gè)數(shù)據(jù)成員賦初值。構(gòu)造函數(shù)初始值是成員名字的一個(gè)列表,每個(gè)名字后面緊跟括號(hào)括起來(lái)的成員初始值。
當(dāng)某個(gè)數(shù)據(jù)成員被構(gòu)造函數(shù)初始值列表忽略時(shí),他將以合成默認(rèn)構(gòu)造函數(shù)相同的方式隱式初始化。所以,第一個(gè)構(gòu)造函數(shù)等價(jià)于:
Sales_data(const string &s):bookNo(s),units_sold(0),revenue(0)();
訪(fǎng)問(wèn)控制和封裝
訪(fǎng)問(wèn)控制符public和private
定義在public說(shuō)明符之后的成員在整個(gè)程序可被訪(fǎng)問(wèn)。
定義在private說(shuō)明符之后的成員可以被類(lèi)的成員函數(shù)訪(fǎng)問(wèn),但是不能被使用該類(lèi)的代碼訪(fǎng)問(wèn)。
Sales_data類(lèi)的新形式
class Sales_data
{
public:
Sales_data()=default;
Sales_data(const string &s):bookNo(s)()
Sales_data(const string &s,unsigned n,double p):bookNo(s),units_sold(n),revenue(p*n){}
Sales_data(istream &)
string isbn() const{return bookNo;}
Sales_data &combine(const Sales_data&);
private:
double avg_price() const;
string bookNo;
unsigned units_sold=0;
double revenue=0.0;
}友元
類(lèi)允許其他類(lèi)或者函數(shù)訪(fǎng)問(wèn)他的非公有成員,方法是令其他類(lèi)或者函數(shù)成為他的友元。如果一個(gè)類(lèi)想把一個(gè)函數(shù)作為他的友元,只需要增加一個(gè)friend關(guān)鍵字開(kāi)始的函數(shù)聲明語(yǔ)句即可
class Sales_data
{
friend Sales_data add(const Sales_data &,const Sales_data&);
friend istream &read(istream&,Sales_data&);
friend ostream &print(ostream&,const Sales_data&)
public:
Sales_data()=default;
Sales_data(const string &s):bookNo(s)()
Sales_data(const string &s,unsigned n,double p):bookNo(s),units_sold(n),revenue(p*n){}
Sales_data(istream &)
string isbn() const{return bookNo;}
Sales_data &combine(const Sales_data&);
private:
double avg_price() const;
string bookNo;
unsigned units_sold=0;
double revenue=0.0;
}友元的聲明只能出現(xiàn)在類(lèi)定義的內(nèi)部。友元不是類(lèi)的成員,也不受他所在區(qū)域訪(fǎng)問(wèn)控制級(jí)別的約束。
類(lèi)的其他特性
可變數(shù)據(jù)成員
在一個(gè)const成員函數(shù)中,若希望修改類(lèi)的某個(gè)數(shù)據(jù)成員,可以通過(guò)在變量的聲明中加入mutable關(guān)鍵字實(shí)現(xiàn)
class screen{
public:
void some_menmber() const;
private:
mutable size_t access_ctr
};
void screen::some_member() const
{
++access_ctr
}返回*this的成員函數(shù)
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;
}
inline Screen &Screen::move(pos r,pos c)
{
pos row=r*width;
cursor=row+c;
return *this;
}move和set一樣,返回的值是對(duì)對(duì)象的引用。
myScreen.move(4,0).set('#');
等同于
myScreen.move(4.0);
myScreen.set('#');
假如我們定義的返回類(lèi)型不是引用,則move的返回值將是*this的副本,因此調(diào)用set只能改變臨時(shí)副本,不能改變myScreen的值
友元類(lèi)
例如,window_mgr類(lèi)的某些成員需要訪(fǎng)問(wèn)screen類(lèi)的內(nèi)部數(shù)據(jù),例如window_mgr的clear函數(shù)將一個(gè)指定的screen類(lèi)的內(nèi)容設(shè)置為空白。
class Screen{
//window_mgr的成員可以訪(fǎng)問(wèn)Screen類(lèi)的私有部分
friend class Window_mgr
//Screen類(lèi)剩余部分
}class Window_mgr{
public:
using ScreenIndex=std::vector<Screen>::size_type
void clear(ScreenIndex);
private:
std::vector<Screen> screens{Screen(24,80,' ')}
};
void Window_mgr::clear(ScreenIndex)
{
Screen &s=screen[i];
s.contens=string(s.height*swidth,' ')
}構(gòu)造函數(shù)再探
構(gòu)造函數(shù)初始值列表
(1)構(gòu)造函數(shù)的初始值有時(shí)必不可少
如果成員是const或者是引用的話(huà),必須將其初始化
class ConstRef
{
public:
ConstRef(int ii);
private:
int i;
const int ci;
int &ri;
};成員ci和ri必須被初始化,如果沒(méi)有為他們提供構(gòu)造函數(shù)初始值的話(huà)將引發(fā)錯(cuò)誤。正確形式應(yīng)該是: ConstRef::ConstRef(int ii):i(ii),ci(ii),ri(i){};
如果成員是const,引用,或者屬于某種未提供默認(rèn)構(gòu)造函數(shù)的類(lèi)類(lèi)型,我們必須通過(guò)構(gòu)造函數(shù)初始值列表為這些成員提供初值。
(2)成員初始化順序
成員初始化的順序與他們?cè)陬?lèi)定義中的出現(xiàn)順序一致。一般來(lái)說(shuō)初始化的順序沒(méi)什么特別要求,不過(guò)如果一個(gè)成員是用另一個(gè)成員來(lái)初始化的,那么著兩個(gè)成員的初始化順序就關(guān)鍵了。
例如
class X
{
int i;
int j;
public:
X(int val):j(val),i(j){}
};而編譯器實(shí)際上是先初始化i,在初始化j,而初始化i的時(shí)候發(fā)現(xiàn)j沒(méi)有值,所以上述構(gòu)造函數(shù)會(huì)發(fā)生錯(cuò)誤。
默認(rèn)構(gòu)造函數(shù)的作用
當(dāng)對(duì)象被默認(rèn)初始化或值初始化時(shí)自動(dòng)執(zhí)行默認(rèn)構(gòu)造函數(shù)。
默認(rèn)初始化在以下情況下發(fā)生:
(1)當(dāng)我們?cè)趬K作用域內(nèi)不適用任何初始值定義一個(gè)非靜態(tài)變量或數(shù)組時(shí)。
(2)當(dāng)一個(gè)類(lèi)本身含有類(lèi)類(lèi)型的成員且使用合成的默認(rèn)構(gòu)造函數(shù)時(shí)
(3)當(dāng)類(lèi)類(lèi)型的成員沒(méi)有在構(gòu)造函數(shù)初始值列表中顯示地初始化時(shí)
值初始化在以下情況發(fā)生:
(1)在數(shù)組初始化的過(guò)程中如果我們提供的初始值數(shù)量少于數(shù)組的大小時(shí)
(2)當(dāng)我們不適用初始值定義一個(gè)局部靜態(tài)變量
使用默認(rèn)構(gòu)造函數(shù)
下面的obj的聲明可以正常通過(guò)
Sales_data obj();//正確,定義了一個(gè)函數(shù)而非對(duì)象 if(obj.isbn()==primer_5th_ed.isbn())//錯(cuò)誤:obj是一個(gè)函數(shù)
但當(dāng)我們?cè)噲D使用obj時(shí),編譯器將報(bào)錯(cuò),提示我們不能使對(duì)函數(shù)使用成員訪(fǎng)問(wèn)運(yùn)算符。因?yàn)閛bj的實(shí)際含義是一個(gè)不接受任何參數(shù)的函數(shù)并且其返回值是Sales_data類(lèi)型的對(duì)象。
如果想定義一個(gè)使用默認(rèn)構(gòu)造函數(shù)進(jìn)行初始化的對(duì)象,正確方法是去掉對(duì)象名之后的空括號(hào)對(duì)。
Sales_data obj;
聚合類(lèi)
滿(mǎn)足一下條件的類(lèi)是聚合類(lèi):
(1)所有成員都是public的
(2)沒(méi)有定義任何構(gòu)造函數(shù)
(3)沒(méi)有類(lèi)內(nèi)初始值
(4)沒(méi)有基類(lèi),也沒(méi)有虛函數(shù)
例:
struct Data
{
int val;
string s;
};類(lèi)的靜態(tài)成員
class Account
{
public:
void calculate(){amount+=amount*interestRate;}
static double rate(){return interestRate;}
static void rate(double);
private:
string owner;
double amount;
static double interestRate;
static double initRate();
}類(lèi)的靜態(tài)成員存在于任何對(duì)象之外,對(duì)象中不包含任何與靜態(tài)數(shù)據(jù)成員有關(guān)的數(shù)據(jù),因此,每個(gè)Account對(duì)象將包含兩個(gè)數(shù)據(jù)成員:owner和amout。只存在一個(gè)interestRate對(duì)象而且他被所有account對(duì)象共享。
靜態(tài)成員函數(shù)也不與任何對(duì)象綁定在一個(gè),他們不包含this指針。作為結(jié)果,靜態(tài)成員函數(shù)不能聲明成const的,而且我們也不能在static函數(shù)體內(nèi)使用this指針。
到此這篇關(guān)于C++ primer類(lèi)的基礎(chǔ)精講的文章就介紹到這了,更多相關(guān)C++類(lèi)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)哈希搜索算法及原理詳解
本文主要介紹了C語(yǔ)言實(shí)現(xiàn)哈希搜索算法及原理詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
Qt帶參數(shù)的信號(hào)和槽函數(shù)舉例詳解
信號(hào)槽的設(shè)計(jì)旨在實(shí)現(xiàn)控件和處理邏輯的解耦合,但在實(shí)際開(kāi)發(fā)中,一對(duì)一的關(guān)系更為常見(jiàn),這篇文章主要介紹了Qt帶參數(shù)的信號(hào)和槽函數(shù)的相關(guān)資料,需要的朋友可以參考下2025-03-03
C語(yǔ)言三個(gè)函數(shù)的模擬實(shí)現(xiàn)詳解
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言三個(gè)函數(shù)的模擬實(shí)現(xiàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-03-03
C++11 call_once 和 once_flag的使用與區(qū)別
本文主要介紹了C++11 call_once 和 once_flag的使用與區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
C語(yǔ)言實(shí)現(xiàn)輸出平均成績(jī)最高學(xué)生的信息
這篇文章主要介紹利用C語(yǔ)言實(shí)現(xiàn)輸出平均成績(jī)最高學(xué)生的信息,文章舉例說(shuō)明并附有詳細(xì)代碼,需要的朋友可以參考一下2021-10-10
數(shù)組中求第K大數(shù)的實(shí)現(xiàn)方法
本篇文章是對(duì)數(shù)組中求第K大數(shù)的實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
C語(yǔ)言中判斷int,long型等變量是否賦值的方法詳解
聲明了int ,long型等局部變量,在利用一些方法給這些變量賦值之后,想判斷這些變量是不是真的被賦初值了,怎么辦2013-07-07

