摘要:三類(lèi)的定義類(lèi)體由成員函數(shù)和成員變量組成一定要注意后面的分號(hào)為定義類(lèi)的關(guān)鍵字,為類(lèi)的名字,中為類(lèi)的主體,注意類(lèi)定義結(jié)束時(shí)后面分號(hào)。在類(lèi)和對(duì)象階段,我們研究類(lèi)的封裝特性。
面向過(guò)程,關(guān)注的是怎么去做,比如在外賣(mài)系統(tǒng)中,強(qiáng)調(diào)點(diǎn)餐,做餐,送餐等一系列動(dòng)作的方法,反映到語(yǔ)言中是函數(shù)方法的實(shí)現(xiàn);而面向?qū)ο?,更關(guān)注的是誰(shuí)去做,比如在外賣(mài)系統(tǒng)中,強(qiáng)調(diào)的是商家,買(mǎi)家和送貨員之間的交互,反映到語(yǔ)言中則是對(duì)象的實(shí)現(xiàn)。
C語(yǔ)言是面向過(guò)程的,關(guān)注的是過(guò)程,分析出求解問(wèn)題的步驟,通過(guò)函數(shù)調(diào)用逐步解決問(wèn)題。
C++是基于面向?qū)ο蟮模P(guān)注的是對(duì)象,將一件事情拆分成不同的對(duì)象,靠對(duì)象之間的交互完成。
這里C++由于兼容C語(yǔ)言,因此既是面向過(guò)程,又是面向?qū)ο蟮模荂++更關(guān)注的是對(duì)象,所以說(shuō)C++是基于面向?qū)ο蟮摹?/p>
在C語(yǔ)言中,結(jié)構(gòu)體只能定義變量,而在C++中,結(jié)構(gòu)體升級(jí)為類(lèi),既可以定義變量,也可以定義函數(shù):
struct Book{ void SetInfo(const char* name, const char* writer, double price)//建立書(shū)本信息 { strcpy(_name, name); strcpy(_writer, writer); _price = price; } void PrintInfo()//打印書(shū)本信息 { cout << _name << endl; cout << _writer << endl; cout << _price << endl; } char _name[20]; char _writer[20]; double _price;};int main(){ Book b1; Book b2; b1.SetInfo("老人與海", "海明威", 12.54); b2.SetInfo("駱駝祥子", "老舍", 14.88); b1.PrintInfo(); cout << endl; b2.PrintInfo(); return 0;}
上面的結(jié)構(gòu)體struct即為一個(gè)類(lèi),{}則形成了一個(gè)類(lèi)域,{}中的內(nèi)容為結(jié)構(gòu)體Book的成員,既有成員變量,又有成員函數(shù)。在C++中,類(lèi)通常用class這個(gè)關(guān)鍵字來(lái)表示。那么struct和class二者之間有什么區(qū)別呢?接下來(lái)我們就來(lái)介紹類(lèi)。
class className{ // 類(lèi)體:由成員函數(shù)和成員變量組成 }; // 一定要注意后面的分號(hào)
class為定義類(lèi)的關(guān)鍵字,ClassName為類(lèi)的名字,{}中為類(lèi)的主體,注意類(lèi)定義結(jié)束時(shí)后面分號(hào)。
類(lèi)中的元素稱為類(lèi)的成員:類(lèi)中的數(shù)據(jù)稱為類(lèi)的屬性或者成員變量; 類(lèi)中的函數(shù)稱為類(lèi)的方法或者成員函數(shù)。
類(lèi)的兩種定義方式:
1.定義和聲明全部放在類(lèi)體中,需要注意的是:成員函數(shù)被定義在類(lèi)體中,編譯器會(huì)默認(rèn)將其當(dāng)作內(nèi)聯(lián)函數(shù),其效用等同于函數(shù)前加上inline關(guān)鍵字,若不知道何為內(nèi)聯(lián)函數(shù),可以參考之前文章中關(guān)于內(nèi)聯(lián)函數(shù)的介紹。
C++入門(mén)
2.聲明與定義分離
聲明放在頭文件中,而定義放在源文件中。
通常情況下,為了代碼的規(guī)范性,更傾向于采用第二種方法來(lái)實(shí)現(xiàn)類(lèi),并且代碼較短的成員函數(shù)直接定義在類(lèi)體中,而代碼較長(zhǎng)的函數(shù)定義在類(lèi)體外。
需要注意的是,類(lèi)中的成員變量均為聲明,它們?cè)趯?shí)例化之前都未被分配空間,不能稱作為定義。
在之前我們討論到class和struct之間有什么區(qū)別,那么這里我們將會(huì)介紹,首先,我們來(lái)了解以下類(lèi)的訪問(wèn)限定符及封裝。
C++實(shí)現(xiàn)封裝的方式:用類(lèi)將對(duì)象的屬性與方法結(jié)合在一塊,讓對(duì)象更加完善,通過(guò)訪問(wèn)權(quán)限選擇性的將其接口提供給外部的用戶使用。
訪問(wèn)限定符的說(shuō)明:
我們知道面向?qū)ο笥腥筇匦裕悍庋b,繼承,多態(tài)。在類(lèi)和對(duì)象階段,我們研究類(lèi)的封裝特性。
首先,封裝指的是將數(shù)據(jù)和操作數(shù)據(jù)的方法進(jìn)行有機(jī)結(jié)合,隱藏對(duì)象的屬性和實(shí)現(xiàn)細(xì)節(jié),僅對(duì)外公開(kāi)接口來(lái)和對(duì)象進(jìn)行交互。
其次,從本質(zhì)上來(lái)說(shuō),封裝是一種管理:舉個(gè)例子,景區(qū)如果不加管理的話,那么景區(qū)的東西很可能會(huì)被不守規(guī)章制度的人破壞,這就好比C語(yǔ)言中為被封裝的代碼隨時(shí)可能被修改,有時(shí)導(dǎo)致出現(xiàn)很大的錯(cuò)誤;那么為了加強(qiáng)管理,保護(hù)景區(qū),就需要設(shè)立景點(diǎn)售票口,同時(shí)安裝監(jiān)控和保安來(lái)保證景區(qū)不被破壞。
類(lèi)也是如此,對(duì)于我們不想被隨意修改的成員變量,我們用private表示其為私有,而為了使用者能夠合理調(diào)用,我們將使用方法封裝成一個(gè)個(gè)的接口即成員函數(shù)用public表示其為公用,至此我們將成員封裝起來(lái),同時(shí)開(kāi)放一些公有的成員函數(shù)對(duì)成員合理的訪問(wèn)。所以封裝本質(zhì)是一種管理,使用封裝可以是代碼更加安全。
類(lèi)定義了一個(gè)新的作用域,類(lèi)的所有成員都在類(lèi)的作用域中。在類(lèi)體外定義成員,需要使用 :: 作用域解析符指明成員屬于哪個(gè)類(lèi)域。
比如,在上面介紹類(lèi)的第二種實(shí)現(xiàn)方式中的代碼,在Book.cpp中定義函數(shù)ShowInfo時(shí)就是指定其為類(lèi)域Book中的成員函數(shù)。
//Book.hclass Book//書(shū){public: void ShowInfo();//展示書(shū)的信息private: char* _name;//書(shū)名 char* _writer;//作者 double _price;//價(jià)格//Book.cpp#include "test.h"void Book::ShowInfo(){ cout << _name << " " << _writer << " " << _price << endl;}};
用類(lèi)類(lèi)型創(chuàng)建對(duì)象的過(guò)程,稱為類(lèi)的實(shí)例化
類(lèi)包含了成員變量和成員函數(shù),那么類(lèi)的大小應(yīng)該如何計(jì)算呢?首先我們來(lái)看看下面這個(gè)代碼的結(jié)果是什么:
class Book{public: void ShowInfo(){}private: char* _name; char* _writer; double _price;};int main(){ cout << sizeof(Book) << endl; return 0;}
可以看到,類(lèi)Book的大小為16,那么這個(gè)16是怎么求出來(lái)的呢?
我們?cè)賮?lái)看一個(gè)代碼:
class C1//類(lèi)中既有成員變量,又有成員函數(shù){public: void fun();private: int _a;};class C2//類(lèi)中只有成員函數(shù){public: void fun();};class C3//類(lèi)中什么都沒(méi)有,即空類(lèi){};int main(){ cout << "C1:" << sizeof(C1) << endl; cout << "C2:" << sizeof(C2) << endl; cout << "C3:" << sizeof(C3) << endl; return 0;}
它的結(jié)果是:
可以看到C1的大小為成員變量_a的大小,C2和C3的大小均為1,說(shuō)明類(lèi)的大小并不包括成員函數(shù)的大小,實(shí)際上如果類(lèi)實(shí)例化時(shí)也會(huì)給成員函數(shù)開(kāi)辟一塊空間,那么當(dāng)一個(gè)類(lèi)創(chuàng)建多個(gè)對(duì)象時(shí),每個(gè)對(duì)象中都會(huì)保存一份成員函數(shù)的代碼,相同代碼保存多次,浪費(fèi)空間。
既然成員函數(shù)不在類(lèi)的大小計(jì)算范圍內(nèi),那么為什么空類(lèi)的大小為1呢?這是因?yàn)橐粋€(gè)類(lèi)創(chuàng)建的時(shí)候需要開(kāi)辟一塊空間來(lái)占位,因此內(nèi)存需要開(kāi)辟一個(gè)字節(jié),這個(gè)字節(jié)的空間是沒(méi)有意義的,其不存儲(chǔ)任何有效數(shù)據(jù),但是其標(biāo)識(shí)了空類(lèi)的存在。
結(jié)論:一個(gè)類(lèi)的大小,實(shí)際就是該類(lèi)中”成員變量”之和,當(dāng)然也要進(jìn)行內(nèi)存對(duì)齊,注意空類(lèi)的大小,空類(lèi)比較特殊,編譯器給了空類(lèi)一個(gè)字節(jié)來(lái)唯一標(biāo)識(shí)這個(gè)類(lèi)。
如果對(duì)結(jié)構(gòu)體內(nèi)存對(duì)齊規(guī)則不熟悉的話,可以參考下面這篇文章:
結(jié)構(gòu)體
不知道你是否注意到,在C和C++實(shí)現(xiàn)棧的代碼中,二者的函數(shù)參數(shù)有些許不同
可以看到,C++的函數(shù)參數(shù)比起C語(yǔ)言實(shí)現(xiàn)的函數(shù)都少了一個(gè)參數(shù),那么問(wèn)題來(lái)了,在下面代碼中s1和s2都調(diào)用Init函數(shù)時(shí),編譯器是怎么區(qū)別是哪個(gè)變量調(diào)用的呢?這就是我們即將要介紹的this指針?biāo)鸬降淖饔昧恕?/p>
int main(){ cpp::Stack s1; cpp::Stack s2; s1.Init(); s2.Init(); s1.Push(1); return 0;}
實(shí)際上,C++編譯器給每個(gè)“非靜態(tài)的成員函數(shù)“增加了一個(gè)隱藏的指針參數(shù),讓該指針指向當(dāng)前對(duì)象(函數(shù)運(yùn)行時(shí)調(diào)用該函數(shù)的對(duì)象),在函數(shù)體中所有成員變量的操作,都是通過(guò)該指針去訪問(wèn)。只不過(guò)所有的操作對(duì)用戶是透明的,即用戶不需要來(lái)傳遞,編譯器自動(dòng)完成。
根據(jù)調(diào)試窗口可以看到this指針就是s1的地址,通過(guò)this指針可以訪問(wèn)s1。
Stack*
void Init() { this->_a = (int*)malloc(sizeof(int) * 4); this->_top = 0; this->_capacity = 4; }
class A{public: void Show() { cout << "Show()" << endl; } void Print() { cout << _a << endl; }private: int _a;};int main(){ A* p = nullptr; p->Show(); p->Print(); return 0;}
那么p->Show(); p->Print();
這兩句代碼能否運(yùn)行成功呢?
可以看到第一句代碼運(yùn)行成功了,而第二句代碼運(yùn)行崩潰了。
這是因?yàn)槌蓡T函數(shù)的地址并不存在于對(duì)象中,而是存在于公共代碼段;而上面的代碼中調(diào)用函數(shù)時(shí)將p傳給了隱含的this指針,并不會(huì)去訪問(wèn)p所指向的空間,就不存在空指針的解引用,因此程序可以并編譯成功。而調(diào)用Show函數(shù)也沒(méi)有對(duì)this指針解引用,因此程序運(yùn)行成功了;調(diào)用Print函數(shù)則會(huì)對(duì)this指針解引用,故程序崩潰了。
結(jié)論:對(duì)于調(diào)用不會(huì)對(duì)this指針解引用的函數(shù),this指針可以為空;而對(duì)于調(diào)用會(huì)對(duì)this指針解引用的函數(shù),this指針不能為空。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/122181.html
摘要:上面需要了解的是這倆個(gè)版本都是破蛹成蝶的版本世界挑戰(zhàn)榜咋才前三還沒(méi)擠進(jìn)去呀,你想想世界上有幾千中編程語(yǔ)言,在其中脫穎出來(lái),可以說(shuō)是天之?huà)勺?,鳳毛麟角了。支持正版圖靈上面買(mǎi)吧,如果沒(méi)錢(qián)買(mǎi)盜版吧學(xué)完以后買(mǎi)本正版支持一下,創(chuàng)作不易是吧 ...
摘要:繼承繼承,就是子類(lèi)繼承父親的特征和行為,使得子類(lèi)具有父類(lèi)的成員變量和方法。此時(shí),被繼承的類(lèi)稱為父類(lèi)或基類(lèi),而繼承的類(lèi)稱為子類(lèi)或派生類(lèi)。,如果存在繼承關(guān)系的時(shí)候,和就不一樣了基類(lèi)中的成員可以在派生類(lèi)中使用,但是基類(lèi)中的成員不能再派生類(lèi)中使用。 ...
摘要:盡管如此,還具有高級(jí)的數(shù)據(jù)類(lèi)型和靈活性。它配備了大量的標(biāo)準(zhǔn)模塊,可用于程序庫(kù)。一些模塊提供如下功能通過(guò)這些很贊的特性,瞬時(shí)化身為面向過(guò)程的語(yǔ)言。開(kāi)發(fā)者可以便捷地將解釋器連接到一個(gè)使用編寫(xiě)的應(yīng)用程序,并能隨時(shí)用作擴(kuò)展。下一部分會(huì)繼續(xù)分享。 【編者按】本文作者是 Abhishek Jaiswal ,擅長(zhǎng) .NET、C#、Python 等多種語(yǔ)言的技術(shù)控。本文中,作者通過(guò)活潑有趣的口吻向大家...
閱讀 2981·2021-10-14 09:42
閱讀 3679·2021-10-11 10:59
閱讀 3012·2019-08-30 11:25
閱讀 3140·2019-08-29 16:25
閱讀 3282·2019-08-26 17:40
閱讀 1326·2019-08-26 13:30
閱讀 1217·2019-08-26 11:46
閱讀 1389·2019-08-23 15:22