最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

5.C++類和對(duì)象(上)

2022-12-04 20:43 作者:限量版范兒  | 我要投稿

面向過(guò)程和面向?qū)ο蟪醪秸J(rèn)識(shí)

C語(yǔ)言是面向過(guò)程的,關(guān)注的是過(guò)程,分析出求解問(wèn)題的步驟,通過(guò)函數(shù)調(diào)用逐步解決問(wèn)題。

C++是基于面向?qū)ο蟮?/strong>,關(guān)注的是對(duì)象,將一件事拆分成不同的對(duì)象,靠對(duì)象之間的交互完成。

以外賣點(diǎn)餐系統(tǒng)為例:

外賣點(diǎn)餐有具體步驟有顧客點(diǎn)餐,商家做餐,外賣員送餐,C語(yǔ)言關(guān)注的是點(diǎn)餐的各個(gè)步驟,即點(diǎn)餐、做餐和送餐的過(guò)程,而C++則是關(guān)注顧客、商家、外賣員這三個(gè)對(duì)象,依托三個(gè)對(duì)象之間的交互來(lái)完成點(diǎn)餐的過(guò)程。

類的引入

C語(yǔ)言中,結(jié)構(gòu)體內(nèi)只能定義變量,而在C++中結(jié)構(gòu)體內(nèi)不僅可以定義變量,還可以定義函數(shù)。

struct Student { void SetStudentInfo(const char* name, const char* gender, int age) { strcpy(_name, name); strcpy(_gender, gender); _age = age; } void PrintStudentInfo() { cout << _name << " " << _gender << " " << _age << endl; } char _name[20]; char _gender[3]; int _age; }; int main() { Student s; s.SetStudentInfo("songxin", "male", 20); s.PrintStudentInfo(); return 0; }

struct是C語(yǔ)言中定義結(jié)構(gòu)體的關(guān)鍵字,在C++中更傾向使用class代替

類的定義

class classname { //函數(shù) //成員 };//注意這里有分號(hào)

class為定義類的關(guān)鍵字,classname為類的名稱。{}中為類的主體,注意類的定義后面要加分號(hào)

類中的元素稱為類的成員:類中的數(shù)據(jù)稱為類的屬性或者成員變量; 類中的函數(shù)稱為類的方法或者成員函數(shù)。

類的兩種定義方式:

  1. 聲明和定義都放在類體中,需要注意的是:成員函數(shù)如果在類體中定義,則默認(rèn)會(huì)給編譯器建議使此函數(shù)成為內(nèi)聯(lián)。

  1. 聲明和定義分離

一般來(lái)說(shuō)我們更青睞第二種方式,即使這樣寫(xiě)會(huì)麻煩一些。

類的訪問(wèn)限定符及封裝

C語(yǔ)言中的結(jié)構(gòu)體并沒(méi)有訪問(wèn)限定符和封裝的概念,我們可以對(duì)結(jié)構(gòu)體中的內(nèi)容隨意訪問(wèn)并且修改,這就很考驗(yàn)程序員的素養(yǎng),人人都可以修改結(jié)構(gòu)體的數(shù)據(jù),這就會(huì)帶來(lái)一些不可預(yù)知的問(wèn)題。

無(wú)規(guī)矩不成方圓,我們無(wú)法去賭每一個(gè)程序員都是能按照規(guī)范編寫(xiě)程式,因此C++引入了訪問(wèn)限定符來(lái)限制我們對(duì)類中成員的權(quán)限。

訪問(wèn)限定符

C++實(shí)現(xiàn)封裝的方式:用類將對(duì)象的屬性與方法結(jié)合在一塊,讓對(duì)象更加完善,通過(guò)訪問(wèn)權(quán)限選擇性的將其接口提供給外部的用戶使用。

訪問(wèn)限定符如上圖,有三種權(quán)限分別設(shè)置為公有、保護(hù)、私有。

訪問(wèn)限定符說(shuō)明

  • public修飾的成員在類外可以直接被訪問(wèn)

  • protected和private修飾的成員在類外不能直接被訪問(wèn)(此處protected和private是類似的)

  • 訪問(wèn)權(quán)限作用域從該訪問(wèn)限定符出現(xiàn)的位置開(kāi)始直到下一個(gè)訪問(wèn)限定符出現(xiàn)時(shí)為止

  • class的默認(rèn)訪問(wèn)權(quán)限為private,struct為public(因?yàn)閟truct要兼容C)

既然被保護(hù)的成員不能被外部通過(guò)對(duì)象所直接訪問(wèn),那么在成員函數(shù)中呢?

class Time { public: Time(int hour = 0, int minute = 0, int second = 0) : _hour(hour), _minute(minute), _second(second) {} Time(Time& t) { _hour = t._hour;//通過(guò)另一個(gè)對(duì)象名直接訪問(wèn)了私有成員函數(shù) _minute = t._minute; _second = t._second; } private: int _hour; int _minute; int _second; };

有兩個(gè)解釋方法:

  1. Time是成員函數(shù)屬于類,而訪問(wèn)限定符限制的是外部,在類域中可以隨意訪問(wèn)。

  2. 相同class的實(shí)例化出的各個(gè)對(duì)象互為友元。

注意:訪問(wèn)限定符僅在編譯時(shí)有用,當(dāng)數(shù)據(jù)映射到內(nèi)存后,沒(méi)有任何訪問(wèn)限定符上的區(qū)別。

來(lái)看看下面這個(gè)問(wèn)題

C++中struct和class的區(qū)別是什么?

C++需要兼容C語(yǔ)言,所以C++中struct可以當(dāng)成結(jié)構(gòu)體去使用。另外C++中struct還可以用來(lái)定義類。和class是定義類是一樣的,區(qū)別是struct的成員默認(rèn)訪問(wèn)方式是public,class是的成員默認(rèn)訪問(wèn)方式是private。

封裝

面向?qū)ο笕筇匦裕?strong>封裝、繼承、多態(tài)。

在類和對(duì)象階段,我們只研究類的封裝特性,那什么是封裝呢?

封裝:將數(shù)據(jù)和操作數(shù)據(jù)的方法進(jìn)行有機(jī)結(jié)合,隱藏對(duì)象的屬性和實(shí)現(xiàn)細(xì)節(jié),僅對(duì)外公開(kāi)接口來(lái)和對(duì)象進(jìn)行交互。

封裝本質(zhì)上是一種管理:我們?nèi)绾喂芾肀R俑呢?比如如果什么都不管,兵馬俑就被隨意破壞了。那么我們首先建了一座房子把兵馬俑給封裝起來(lái)。但是我們目的不是全封裝起來(lái),不讓別人看。所以我們開(kāi)放了售票通道,可以買票突破封裝在合理的監(jiān)管機(jī)制下進(jìn)去參觀。類也是一樣,我們使用類數(shù)據(jù)和方法都封裝到一下。不想給別人看到的,我們使用protected/private把成員封裝起來(lái)。開(kāi)放一些共有的成員函數(shù)對(duì)成員合理的訪問(wèn)。所以封裝本質(zhì)是管理。

類的作用域

類新定義了一個(gè)作用域,類的所以成員都在類的作用域中。在類外定義成員,需要使用::作用域解析符來(lái)指明成員屬于哪個(gè)類。

class Person { public: void PrintPersonInfo(); private: char _name[20]; char _gender[3]; int _age; }; //類外定義成員函數(shù)需要加上::作用域解析符 void Person::PrintPersonInfo() { cout << _name << endl; cout << _gender << endl; cout << _age << endl; }

總之,封裝有利于管理類的對(duì)象,讓對(duì)象的處理操作更加統(tǒng)一,對(duì)于一些我們不想給外界直接訪問(wèn)的成員可以設(shè)置為私有,對(duì)于需要被外部使用的成員設(shè)置為公有,這樣的封裝設(shè)計(jì)讓我們的程式更加規(guī)范安全。

類的實(shí)例化

用類去創(chuàng)建對(duì)象的過(guò)程,稱為類的實(shí)例化。

  1. 類形象的說(shuō)就是一個(gè)模具,我們可以使用設(shè)計(jì)好的模具去制作出實(shí)體對(duì)象。

  2. 類只聲明了類有哪些成員,而并沒(méi)有為成員分配內(nèi)存空間。

  3. 一個(gè)類可以實(shí)例化出多個(gè)對(duì)象,實(shí)例化出的對(duì)象占用實(shí)際的物理空間,存儲(chǔ)類成員變量。

  4. 做個(gè)比方。類實(shí)例化出對(duì)象就像現(xiàn)實(shí)中使用建筑設(shè)計(jì)圖建造出房子,類就像是設(shè)計(jì)圖,只設(shè)計(jì)出需要什么東西,但是并沒(méi)有實(shí)體的建筑存在,同樣類也只是一個(gè)設(shè)計(jì),實(shí)例化出的對(duì)象才能實(shí)際存儲(chǔ)數(shù)據(jù),占用物理空間。


類對(duì)象模型

計(jì)算類對(duì)象的大小

class Person { public: void PrintPersonInfo(); private: int _age; }; int main() { Person p; cout << sizeof(Person) << endl; ? ?cout << sizeof(p) << endl; return 0; }

輸出:

4

4

這里使用sizeof計(jì)算Person類的大小和Person類定義出來(lái)的對(duì)象大小是一樣的。

類對(duì)象的存儲(chǔ)方式

  • 如果對(duì)象中包含類中的所有成員

缺陷:每個(gè)對(duì)象中成員變量是不同的,但是調(diào)用同一份函數(shù),如果按照此種方式存儲(chǔ),當(dāng)一個(gè)類創(chuàng)建多個(gè)對(duì)象時(shí),每個(gè)對(duì)象中都會(huì)保存一份代碼,相同代碼保存多次,浪費(fèi)空間。那么如何解決呢?

  • 只保存成員變量,成員函數(shù)指令放在公共的代碼段

這里需要給大小 說(shuō)說(shuō)內(nèi)存中的分區(qū),C++程序的內(nèi)存格局通常分為四個(gè)區(qū):靜態(tài)區(qū)(static area),代碼區(qū)(code area),棧區(qū)(stack area),堆區(qū)(heap area)(即自由存儲(chǔ)區(qū))。靜態(tài)區(qū)存放全局變量,靜態(tài)數(shù)據(jù)和常量;所有類成員函數(shù)和非成員函數(shù)代碼存放在代碼區(qū);為運(yùn)行函數(shù)而分配的局部變量、函數(shù)參數(shù)、返回?cái)?shù)據(jù)、返回地址等存放在棧區(qū);余下的空間都被稱為堆區(qū)。

根據(jù)這個(gè)解釋,我們可以得知在類的定義時(shí),類成員函數(shù)是被放在代碼區(qū),而類的靜態(tài)成員變量是存儲(chǔ)在靜態(tài)區(qū)的,即實(shí)例化的對(duì)象并不包括靜態(tài)變量的創(chuàng)建,因而它是屬于類的。對(duì)于非靜態(tài)成員變量,我們是在類的實(shí)例化過(guò)程中(構(gòu)造對(duì)象)才在棧區(qū)或者堆區(qū)為其分配內(nèi)存,是為每個(gè)對(duì)象生成一個(gè)拷貝,所以它是屬于對(duì)象的。

那么肯定是第二種存儲(chǔ)方式更節(jié)省空間,那么實(shí)際中到底是哪種存儲(chǔ)方式呢?

依然使用剛剛的代碼,簡(jiǎn)單變形一下

//即有成員變量又有成員函數(shù) class Person1 { public: void PrintPersonInfo(); private: int _age; }; //僅有成員變量 class Person2 { private: int _age; }; //空類 class Person3 {}; int main() { cout << sizeof(Person1) << endl; ? cout << sizeof(Person2) << endl; ? ?cout << sizeof(Person3) << endl; return 0; }

輸出:

4

4

1

很顯然,我們計(jì)算對(duì)象的大小和是否含有成員函數(shù)無(wú)關(guān)(也就是說(shuō)成員函數(shù)存儲(chǔ)在代碼區(qū)),對(duì)象中也不存放成員函數(shù)的指針。

結(jié)論:一個(gè)類的大小,實(shí)際就是該類中”成員變量”大小之和,當(dāng)然也要進(jìn)行內(nèi)存對(duì)齊,注意空類的大小,空類比較特殊,編譯器給了空類一個(gè)字節(jié)來(lái)唯一標(biāo)識(shí)這個(gè)類。

注:這里的成員變量之和并不是簡(jiǎn)單的字節(jié)數(shù)相加,而是還要遵循內(nèi)存對(duì)齊規(guī)則。

結(jié)構(gòu)體內(nèi)存對(duì)齊規(guī)則

  1. 第一個(gè)成員在與結(jié)構(gòu)體偏移量為0的地址處。

  2. 其他成員變量要對(duì)齊到某個(gè)數(shù)字(對(duì)齊數(shù))的整數(shù)倍的地址處。

注意:對(duì)齊數(shù) = 編譯器默認(rèn)的一個(gè)對(duì)齊數(shù)與該成員大小的較小值。
VS中默認(rèn)的對(duì)齊數(shù)為8;

  1. 結(jié)構(gòu)體總大小為:最大對(duì)齊數(shù)(所有變量類型最大者與默認(rèn)對(duì)齊參數(shù)取最?。┑恼麛?shù)倍。

  2. 如果嵌套了結(jié)構(gòu)體的情況,嵌套的結(jié)構(gòu)體對(duì)齊到自己的最大對(duì)齊數(shù)的整數(shù)倍處,結(jié)構(gòu)體的整體大小就是所有最大對(duì)齊數(shù)(含嵌套結(jié)構(gòu)體的對(duì)齊數(shù))的整數(shù)倍。

這里的規(guī)則和C語(yǔ)言的規(guī)則是一樣的,就不再展開(kāi)講了。

this指針

class Date { public: void Display() { cout << _year << "-" << _month << "-" << _day << endl; } void SetDate(int year, int month, int day) { _year = year; _month = month; _day = day; } private: int _year; // 年 int _month; // 月 int _day; // 日 }; int main() { Date d1, d2; d1.SetDate(2018, 5, 1); d2.SetDate(2018, 7, 1); d1.Display(); d2.Display(); return 0; }

對(duì)于上述程序,d1和d2各自有不同的內(nèi)存空間,可我們的成員函數(shù)SetDate中卻并沒(méi)有指定要對(duì)哪一個(gè)對(duì)象的成員進(jìn)行操作,那么當(dāng)d1調(diào)用時(shí)函數(shù)是如何知道操作的對(duì)象是哪一個(gè)呢?

C++中通過(guò)引入this指針解決該問(wèn)題,即: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)完成。

注:實(shí)參形參中不能顯式地去寫(xiě)this指針。

因此程序還可以這樣寫(xiě):

class Date { public: void Display() { cout << this->_year << "-" << this->_month << "-" << this->_day << endl; } void SetDate(int year, int month, int day) { this->_year = year; this->_month = month; this->_day = day; } private: int _year; // 年 int _month; // 月 int _day; // 日 }; int main() { Date d1, d2; d1.SetDate(2018, 5, 1); d2.SetDate(2018, 7, 1); d1.Display(); d2.Display(); return 0; }

實(shí)際上我們不寫(xiě)this->成員,比那一起也會(huì)這樣給我們處理。

this指針的特性

  1. this指針的類型:TypeOfClass* const,this指針在函數(shù)體內(nèi)不可修改。

  2. 只能在“成員函數(shù)”的內(nèi)部使用。

  3. this指針本質(zhì)上其實(shí)是一個(gè)成員函數(shù)的形參,是對(duì)象調(diào)用成員函數(shù)時(shí),將對(duì)象地址作為實(shí)參傳遞給this形參,對(duì)象中并不存儲(chǔ)this指針。

  4. this指針是成員函數(shù)第一個(gè)隱含的指針形參,一般情況由編譯器通過(guò)ecx寄存器自動(dòng)傳遞,不需要用戶傳遞。

如下兩種寫(xiě)法并無(wú)差別

關(guān)于this指針

this指針的存儲(chǔ)位置在哪里?

臨時(shí)變量都是存儲(chǔ)在棧上的,因此this指針作為形參,存儲(chǔ)在棧區(qū)。

this指針可以為空指針嗎?

class A { public: void PrintA() { cout << _a << endl; } void Show() { cout << "Show()" << endl; } private: int _a; }; int main() { A* p = nullptr; ? ?p->Show(); ? ?p->PrintA(); }

要知道0地址處我們是沒(méi)有訪問(wèn)權(quán)限的,若非法訪問(wèn)程序會(huì)崩潰。

這里的程序其實(shí)Show是可以正常調(diào)用,而PrintA是無(wú)法正常運(yùn)行的。

來(lái)看看PrintA函數(shù)體的匯編指令(部分)

首先Show可以正常調(diào)用,說(shuō)明并不是p為空指針了就無(wú)法通過(guò)p調(diào)用函數(shù)了,調(diào)用函數(shù)訪問(wèn)的是函數(shù)的地址,而雖然它們都是成員函數(shù),但是它們都存儲(chǔ)在公共代碼區(qū),并不是在0地址處去訪問(wèn)函數(shù),所以調(diào)用函數(shù)并沒(méi)有問(wèn)題,問(wèn)題出在PrintA中的?cout << _a << endl;語(yǔ)句訪問(wèn)了_a成員變量,而p又是指向0地址處,因此就相當(dāng)于訪問(wèn)了0地址處的數(shù)據(jù),因此程序崩潰。

this指針可以為空指針,但切忌通過(guò)nullptr去訪問(wèn)指向的數(shù)據(jù)

鏈接:https://www.dianjilingqu.com/628685.html

5.C++類和對(duì)象(上)的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
康马县| 铜川市| 页游| 阿坝县| 台前县| 阿城市| 闻喜县| 石门县| 庆阳市| 准格尔旗| 珲春市| 双城市| 乐至县| 陵水| 临泽县| 丹寨县| 梅州市| 获嘉县| 九江县| 湘西| 西青区| 二连浩特市| 修武县| 黑水县| 南投市| 慈利县| 宕昌县| 孟州市| 南澳县| 晋中市| 惠州市| 长沙县| 东丽区| 紫云| 江山市| 富源县| 泰来县| 明光市| 汉中市| 定襄县| 明溪县|