C++ primer類的基礎(chǔ)精講
定義抽象數(shù)據(jù)類型
初探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
對于isbn成員函數(shù)的調(diào)用: total.isbn();
當(dāng)我們調(diào)用成員函數(shù)時,實則上是在替某個對象調(diào)用它。在上面的調(diào)用中,當(dāng)isbn返回bookNo時,實際上隱式地返回total.bookNo.
成員函數(shù)通過一個名為this的額外隱式參數(shù)來訪問調(diào)用它的那個對象。當(dāng)我們調(diào)用一個成員函數(shù)時,用請求該函數(shù)的對象地址初始化this。例如,如果調(diào)用total.isbn(),編譯器負責(zé)把total的地址傳遞給isbn的隱式形參this,可以等價認為編譯器將該調(diào)用重寫成Sales_data::isbn(&total),調(diào)用Sales_data時的isbn成員時傳入了total的地址。
在成員函數(shù)內(nèi)部,我們可以直接使用調(diào)用該函數(shù)的對象的成員,而無須通過成員訪問運算符來做到這一點,因為this所指的正是這個對象。任何對類成員的直接訪問都被看做this的隱式調(diào)用,例如,isbn在使用bookNo時,隱式地使用this指向的成員,就如同this->bookNo一樣。
構(gòu)造函數(shù)
定義:類通過一個或幾個特殊的成員函數(shù)來控制其對象的初始化,這些函數(shù)叫做構(gòu)造函數(shù)。
無論何時,只要類的對象被創(chuàng)建,就會執(zhí)行構(gòu)造函數(shù)。
構(gòu)造函數(shù)的名字和類名一樣,構(gòu)造函數(shù)沒有返回類型,一個類可以擁有多個構(gòu)造函數(shù),但每個構(gòu)造函數(shù)之間必須在參數(shù)數(shù)量或參數(shù)類型上存在不同。且構(gòu)造函數(shù)不能被聲明成const。
當(dāng)一個類沒有定義任何構(gòu)造函數(shù)時,編譯器會給類自動添加一個默認構(gòu)造函數(shù),該構(gòu)造函數(shù)無須任何實參對對象進行初始化。
對前面的Sales_data類進行編寫構(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的含義
如果需要默認構(gòu)造函數(shù)起作用,那么可以在參數(shù)列表后面寫上=default來要求編譯器生成默認構(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òu)造函數(shù)的寫法,該部分稱為構(gòu)造函數(shù)初始值列表。
負責(zé)為新創(chuàng)建的對象的一個或幾個數(shù)據(jù)成員賦初值。構(gòu)造函數(shù)初始值是成員名字的一個列表,每個名字后面緊跟括號括起來的成員初始值。
當(dāng)某個數(shù)據(jù)成員被構(gòu)造函數(shù)初始值列表忽略時,他將以合成默認構(gòu)造函數(shù)相同的方式隱式初始化。所以,第一個構(gòu)造函數(shù)等價于:
Sales_data(const string &s):bookNo(s),units_sold(0),revenue(0)();
訪問控制和封裝
訪問控制符public和private
定義在public說明符之后的成員在整個程序可被訪問。
定義在private說明符之后的成員可以被類的成員函數(shù)訪問,但是不能被使用該類的代碼訪問。
Sales_data類的新形式
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; }
友元
類允許其他類或者函數(shù)訪問他的非公有成員,方法是令其他類或者函數(shù)成為他的友元。如果一個類想把一個函數(shù)作為他的友元,只需要增加一個friend關(guān)鍵字開始的函數(shù)聲明語句即可
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)在類定義的內(nèi)部。友元不是類的成員,也不受他所在區(qū)域訪問控制級別的約束。
類的其他特性
可變數(shù)據(jù)成員
在一個const成員函數(shù)中,若希望修改類的某個數(shù)據(jù)成員,可以通過在變量的聲明中加入mutable關(guān)鍵字實現(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一樣,返回的值是對對象的引用。
myScreen.move(4,0).set('#');
等同于
myScreen.move(4.0);
myScreen.set('#');
假如我們定義的返回類型不是引用,則move的返回值將是*this的副本,因此調(diào)用set只能改變臨時副本,不能改變myScreen的值
友元類
例如,window_mgr類的某些成員需要訪問screen類的內(nèi)部數(shù)據(jù),例如window_mgr的clear函數(shù)將一個指定的screen類的內(nèi)容設(shè)置為空白。
class Screen{ //window_mgr的成員可以訪問Screen類的私有部分 friend class Window_mgr //Screen類剩余部分 }
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ù)的初始值有時必不可少
如果成員是const或者是引用的話,必須將其初始化
class ConstRef { public: ConstRef(int ii); private: int i; const int ci; int &ri; };
成員ci和ri必須被初始化,如果沒有為他們提供構(gòu)造函數(shù)初始值的話將引發(fā)錯誤。正確形式應(yīng)該是: ConstRef::ConstRef(int ii):i(ii),ci(ii),ri(i){};
如果成員是const,引用,或者屬于某種未提供默認構(gòu)造函數(shù)的類類型,我們必須通過構(gòu)造函數(shù)初始值列表為這些成員提供初值。
(2)成員初始化順序
成員初始化的順序與他們在類定義中的出現(xiàn)順序一致。一般來說初始化的順序沒什么特別要求,不過如果一個成員是用另一個成員來初始化的,那么著兩個成員的初始化順序就關(guān)鍵了。
例如
class X { int i; int j; public: X(int val):j(val),i(j){} };
而編譯器實際上是先初始化i,在初始化j,而初始化i的時候發(fā)現(xiàn)j沒有值,所以上述構(gòu)造函數(shù)會發(fā)生錯誤。
默認構(gòu)造函數(shù)的作用
當(dāng)對象被默認初始化或值初始化時自動執(zhí)行默認構(gòu)造函數(shù)。
默認初始化在以下情況下發(fā)生:
(1)當(dāng)我們在塊作用域內(nèi)不適用任何初始值定義一個非靜態(tài)變量或數(shù)組時。
(2)當(dāng)一個類本身含有類類型的成員且使用合成的默認構(gòu)造函數(shù)時
(3)當(dāng)類類型的成員沒有在構(gòu)造函數(shù)初始值列表中顯示地初始化時
值初始化在以下情況發(fā)生:
(1)在數(shù)組初始化的過程中如果我們提供的初始值數(shù)量少于數(shù)組的大小時
(2)當(dāng)我們不適用初始值定義一個局部靜態(tài)變量
使用默認構(gòu)造函數(shù)
下面的obj的聲明可以正常通過
Sales_data obj();//正確,定義了一個函數(shù)而非對象 if(obj.isbn()==primer_5th_ed.isbn())//錯誤:obj是一個函數(shù)
但當(dāng)我們試圖使用obj時,編譯器將報錯,提示我們不能使對函數(shù)使用成員訪問運算符。因為obj的實際含義是一個不接受任何參數(shù)的函數(shù)并且其返回值是Sales_data類型的對象。
如果想定義一個使用默認構(gòu)造函數(shù)進行初始化的對象,正確方法是去掉對象名之后的空括號對。
Sales_data obj;
聚合類
滿足一下條件的類是聚合類:
(1)所有成員都是public的
(2)沒有定義任何構(gòu)造函數(shù)
(3)沒有類內(nèi)初始值
(4)沒有基類,也沒有虛函數(shù)
例:
struct Data { int val; string s; };
類的靜態(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(); }
類的靜態(tài)成員存在于任何對象之外,對象中不包含任何與靜態(tài)數(shù)據(jù)成員有關(guān)的數(shù)據(jù),因此,每個Account對象將包含兩個數(shù)據(jù)成員:owner和amout。只存在一個interestRate對象而且他被所有account對象共享。
靜態(tài)成員函數(shù)也不與任何對象綁定在一個,他們不包含this指針。作為結(jié)果,靜態(tài)成員函數(shù)不能聲明成const的,而且我們也不能在static函數(shù)體內(nèi)使用this指針。
到此這篇關(guān)于C++ primer類的基礎(chǔ)精講的文章就介紹到這了,更多相關(guān)C++類內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++11 call_once 和 once_flag的使用與區(qū)別
本文主要介紹了C++11 call_once 和 once_flag的使用與區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06