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