亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

C++ 類與對(duì)象(上)

alanoddsoff / 1818人閱讀

摘要:中默認(rèn)的對(duì)齊數(shù)為結(jié)構(gòu)體總大小為最大對(duì)齊數(shù)所有變量類型最大者與默認(rèn)對(duì)齊參數(shù)取最小的整數(shù)倍。性能原因數(shù)據(jù)結(jié)構(gòu)尤其是棧應(yīng)該盡可能地在自然邊界上對(duì)齊。

類的引入

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

struct Student{	//在類里面定義函數(shù)	void SetStudentInfo(const char* name, const char* gender, int age)	{		strcpy(_name, name);		strcpy(_gender, gender);		_age = age;	}		//在類里面定義函數(shù)	void PrintStudentInfo()	{		cout<<_name<<" "<<_gender<<" "<<_age<<endl;	}    //在類里面定義變量char _name[20];char _gender[3];int _age;};int main(){	Student s;	s.SetStudentInfo("Peter", "男", 18);	return 0;}

上面結(jié)構(gòu)體的定義,在C++中更喜歡用class來(lái)代替

類的定義

class className{// 類體:由成員函數(shù)和成員變量組成}; // 一定要注意后面的分號(hào)

class為定義類的關(guān)鍵字,ClassName為類的名字,{}中為類的主體,注意類定義結(jié)束時(shí)后面分號(hào)。

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

類的兩種定義方式:

  1. 聲明和定義全部放在類體中,需要注意:成員函數(shù)如果在類中定義,編譯器可能會(huì)將其當(dāng)成內(nèi)聯(lián)函數(shù)處

  2. 聲明放在.h文件中,類的定義放在.cpp文件中

一般情況下,更期望采用第二種方式。

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

訪問(wèn)限定符

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

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

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

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

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

  4. class的默認(rèn)訪問(wèn)權(quán)限為private,struct為public(因?yàn)閟truct要兼容C)
    注意:訪問(wèn)限定符只在編譯時(shí)有用,當(dāng)數(shù)據(jù)映射到內(nèi)存后,沒(méi)有任何訪問(wèn)限定符上的區(qū)別

【面試題】
問(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是struct的成員默認(rèn)訪問(wèn)方式
是private。

封裝

【面試題】 面向?qū)ο蟮娜筇匦裕悍庋b、繼承、多態(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è)新的作用域,類的所有成員都在類的作用域中。在類體外定義成員,需要使用 :: 作用域解析符指明成員屬于哪個(gè)類域

class Person{public:	void PrintPersonInfo();private:char _name[20];char _gender[3];int _age;};// 這里需要指定PrintPersonInfo是屬于Person這個(gè)類域void Person::PrintPersonInfo(){	cout<<_name<<" "_gender<<" "<<_age<<endl;}

短小的的成員函數(shù),直接在類里面定義,就默認(rèn)是內(nèi)聯(lián)函數(shù)

代碼長(zhǎng)的成員函數(shù)建議聲明和定義分離

私有的數(shù)據(jù)可以通過(guò)共有的函數(shù)來(lái)操作,比如棧,棧的成員變量可以私有,在外部就無(wú)法訪問(wèn)成員變量,要想對(duì)成員變量進(jìn)行操作可以使用公有的成員函數(shù)。

類的實(shí)例化

  1. 類只是一個(gè)模型一樣的東西,限定了類有哪些成員,定義出一個(gè)類并沒(méi)有分配實(shí)際的內(nèi)存空間來(lái)存儲(chǔ)它
  2. 一個(gè)類可以實(shí)例化出多個(gè)對(duì)象,實(shí)例化出的對(duì)象 占用實(shí)際的物理空間,存儲(chǔ)類成員變量
  3. 做個(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 A{public:void PrintA(){	cout<<_a<<endl;}    private:char _a;};

問(wèn)題:類中既可以有成員變量,又可以有成員函數(shù),那么一個(gè)類的對(duì)象中包含了什么?如何計(jì)算一個(gè)類的大小?

答案:一個(gè)類的對(duì)象中只包含了成員變量,一個(gè)類的大小只包括成員變量的大小,根據(jù)內(nèi)存對(duì)齊方式來(lái)確定類的大小。

類對(duì)象的存儲(chǔ)方式猜測(cè)

  • 對(duì)象中包含類的各個(gè)成員

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

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

一個(gè)類實(shí)例化出N個(gè)對(duì)象,每個(gè)對(duì)象的成員變量可以存儲(chǔ)不同的值,但是調(diào)用的函數(shù)卻是同一個(gè),如果每個(gè)對(duì)象都放成員函數(shù),而這些成員函數(shù)卻是一樣的,就會(huì)浪費(fèi)空間。

我們?cè)偻ㄟ^(guò)對(duì)下面的不同對(duì)象分別獲取大小來(lái)分析看下

// 類中既有成員變量,又有成員函數(shù)class A1 {public:void f1(){}private:int _a;};// 類中僅有成員函數(shù)class A2 {public:void f2() {}};// 類中什么都沒(méi)有---空類class A3{};

sizeof(A1) : 4

sizeof(A2) : 1

sizeof(A3) : 1

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

為什么給了1個(gè)字節(jié)而不是0個(gè)字節(jié)呢?

開(kāi)1個(gè)字節(jié)不是為了存數(shù)據(jù),是為了占位,表示其存在。

如果一個(gè)類沒(méi)有成員,那么他的對(duì)象需要給1byte進(jìn)行占位來(lái)標(biāo)識(shí)對(duì)象存在,這1byte不存儲(chǔ)有效數(shù)據(jù)

結(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

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

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

【面試題】

  1. 結(jié)構(gòu)體怎么對(duì)齊? 為什么要進(jìn)行內(nèi)存對(duì)齊

    1. 平臺(tái)原因(移植原因): 不是所有的硬件平臺(tái)都能訪問(wèn)任意地址上的任意數(shù)據(jù)的;某些硬件平臺(tái)只能在某些地址處取某些特定類型的數(shù)據(jù),否則拋出硬件異常。

    2. 性能原因: 數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能地在自然邊界上對(duì)齊。 原因在于,為了訪問(wèn)未對(duì)齊的內(nèi)存,處理需要作兩次內(nèi)存訪問(wèn);而對(duì)齊的內(nèi)存訪問(wèn)僅需要一次訪問(wèn)

  2. 如何讓結(jié)構(gòu)體按照指定的對(duì)齊參數(shù)進(jìn)行對(duì)齊

    使用#pragma pack

  3. 如何知道結(jié)構(gòu)體中某個(gè)成員相對(duì)于結(jié)構(gòu)體起始位置的偏移量

    C語(yǔ)言中的宏offsetof可以計(jì)算,本質(zhì)上是:#define my_offsetof(s, m) (size_t)&(((s*)(0))->m)

    (s*)(0)意思是將0地址變成一個(gè)s類型的結(jié)構(gòu)體的起始地址,再對(duì)引用某個(gè)成員(s *)(0)->m,對(duì)該成員取地址

    &((s *)(0)->m),得到的是該成員的地址,而因?yàn)槠鹗嫉刂窞?,所以該成員的地址就是相對(duì)起始位置的偏移量。

  4. 什么是大小端?如何測(cè)試某臺(tái)機(jī)器是大端還是小端,有沒(méi)有遇到過(guò)要考慮大小端的場(chǎng)景

    大小端在計(jì)算機(jī)業(yè)界,Endian表示數(shù)據(jù)在存儲(chǔ)器中的存放順序。

    大端模式,是指數(shù)據(jù)的高字節(jié)保存在內(nèi)存的低地址中,而數(shù)據(jù)的低字節(jié)保存在內(nèi)存的高地址中,這樣的存儲(chǔ)模式有點(diǎn)兒類似于把數(shù)據(jù)當(dāng)作字符串順序處理:地址由小向大增加,而數(shù)據(jù)從高位往低位放;

    小端模式,是指數(shù)據(jù)的高字節(jié)保存在內(nèi)存的高地址中,而數(shù)據(jù)的低字節(jié)保存在內(nèi)存的低地址中,這種存儲(chǔ)模式將地址的高低和數(shù)據(jù)位權(quán)有效地結(jié)合起來(lái),高地址部分權(quán)值高,低地址部分權(quán)值低,和我們的邏輯方法一致。

    比如一個(gè)整型10,將它的32位按十六進(jìn)制從高位到低位表示:00 00 00 0A

    在大端中的存儲(chǔ)方式是:

    小端中的存儲(chǔ)方式是:

    測(cè)試大小端(使用共用體Union):

    union U {	char a;	int b;};int main(){	U u1;	u1.b = 1;	if (u1.a == 1)	{		printf("小端/n");	}	else		printf("大端/n");	return 0;}

    原理:U中的a和b是共用一塊空間的,a占一個(gè)字節(jié),能使用的只有b的一個(gè)低地址處的字節(jié)

    如果當(dāng)前機(jī)器是小端,則b=1,按照地址從低到高,存儲(chǔ)方式就是:01 00 00 00

    a能夠訪問(wèn)的就是低地址處的01

    如果當(dāng)前機(jī)器是大端,則b=1,按照地址從低到高,存儲(chǔ)方式就是:0 00 00 01

    a能夠訪問(wèn)的就是低地址處的00

this指針

this指針的引出

我們先來(lái)定義一個(gè)日期類Date

class Date{public :void Print (){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.Print();    d2.Print();    return 0;}

對(duì)于上述類,有這樣的一個(gè)問(wèn)題:

Date類中有SetDate與Print兩個(gè)成員函數(shù),函數(shù)體中沒(méi)有關(guān)于不同對(duì)象的區(qū)分,那當(dāng)s1調(diào)用SetDate函數(shù)
時(shí),該函數(shù)是如何知道應(yīng)該設(shè)置s1對(duì)象,而不是設(shè)置s2對(duì)象呢?

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ù)調(diào)用時(shí),實(shí)際上是這樣的:

//規(guī)定this指針默認(rèn)放在第一個(gè)參數(shù)位置d1.SetDate(&d1,2018,5,1);d2.SetDate(&d2,2018,7,1);d1.Print(&d1);d2.Print(&d2);

但我們調(diào)用時(shí)不得私自加上這個(gè)指針參數(shù)

并且在定義類成員函數(shù)時(shí),實(shí)際上也是這樣的

//在定義成員函數(shù)時(shí)也可以這么寫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;	}

我們只是看上去沒(méi)有傳參數(shù), 實(shí)際上是傳了調(diào)用Print函數(shù)的類的地址。

this指針的特性

  1. this指針的類型:類類型* const
  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)傳遞,不需要用戶傳遞

【面試題】

  1. this指針存在哪里?

  2. this指針可以為空嗎?

我們先看下面的代碼,再回答這兩個(gè)問(wèn)題

// 1.下面程序能編譯通過(guò)嗎?// 2.下面程序會(huì)崩潰嗎?在哪里崩潰class A{public:void PrintA(){	cout<<_a<<endl;}void Show(){	cout<<"Show()"<<endl;}private:int _a;};int main(){    Date* p = NULL;    p->PrintA();    p->Show();}

答案:p->PrintA()崩潰,p->Show()通過(guò),因?yàn)镻rintA中需要用到this指針,并對(duì)this指針指向的類的成員變量進(jìn)行訪問(wèn),而p是一個(gè)空指針,沒(méi)有指向任何類,所以函數(shù)內(nèi)部對(duì)_a(實(shí)際上是this-> _a)的引用失敗

而對(duì)于p->Show(),Show函數(shù)在公共代碼段,所以p對(duì)其不用解引用,并且Show()函數(shù)中,并沒(méi)有對(duì)p進(jìn)行解引用,所以不會(huì)引發(fā)錯(cuò)誤。

最開(kāi)始兩個(gè)問(wèn)題的答案:

1.this指針是存放在棧上的,因?yàn)樗且粋€(gè)形參。

注:vs下是在ecx這個(gè)寄存器下存放的,因?yàn)閠his指針要被多次使用,所以把它放在寄存器中,方便快速訪問(wèn)。

2.如上面代碼所示,this指針是可以為空的,只要在類成員函數(shù)內(nèi)不使用this指針。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/122190.html

相關(guān)文章

  • Python方法(二) - 類與繼承

    摘要:在類內(nèi)部的方法中使用時(shí)。類的私有方法兩個(gè)下劃線開(kāi)頭,聲明該方法為私有方法,不能在類地外部調(diào)用。先在本類中查找調(diào)用的方法,找不到才去基類中找。如果在繼承元組中列了一個(gè)以上的類,那么它就被稱作多重繼承。 類定義 類對(duì)象:創(chuàng)建一個(gè)類之后,可以通過(guò)類名訪問(wèn)、改變其屬性、方法 實(shí)例對(duì)象:類實(shí)例化后,可以使用其屬性,可以動(dòng)態(tài)的為實(shí)例對(duì)象添加屬性(類似javascript)而不影響類對(duì)象。 類...

    DevWiki 評(píng)論0 收藏0
  • javascript對(duì)象、類與原型鏈

    摘要:下面定義一個(gè)構(gòu)造函數(shù)不過(guò)這樣寫這個(gè)函數(shù),每個(gè)對(duì)象都會(huì)包括一部分,太浪費(fèi)內(nèi)存。原型鏈與繼承在學(xué)習(xí)原型鏈之前我們一定要區(qū)分清楚是構(gòu)造函數(shù)的屬性,而是對(duì)象的屬性。但對(duì)象形式不等于基本類型。用來(lái)判斷對(duì)象是否某個(gè)構(gòu)造函數(shù)的實(shí)例。 js是一個(gè)基于對(duì)象的語(yǔ)言,所以本文研究一下js對(duì)象和類實(shí)現(xiàn)的過(guò)程和原理。 對(duì)象的屬性及屬性特性 下面是一個(gè)對(duì)象的各個(gè)部分: var person = { name:...

    adam1q84 評(píng)論0 收藏0
  • C++之繼承

    摘要:基類中的構(gòu)造函數(shù)和析構(gòu)函數(shù)不能被繼承,在派生類中需要定義新的構(gòu)造函數(shù)和析構(gòu)函數(shù),私有成員不能被繼承。對(duì)象訪問(wèn)在派生類外部,通過(guò)派生類的對(duì)象對(duì)從基類繼承來(lái)的成員的訪問(wèn)。 ...

    不知名網(wǎng)友 評(píng)論0 收藏0
  • JavaScript基礎(chǔ): 類與繼承

    摘要:類的方法相當(dāng)于之前我們定義在構(gòu)造函數(shù)的原型上。的構(gòu)造函數(shù)中調(diào)用其目的就是調(diào)用父類的構(gòu)造函數(shù)。是先創(chuàng)建子類的實(shí)例,然后在子類實(shí)例的基礎(chǔ)上創(chuàng)建父類的屬性。 前言   首先歡迎大家關(guān)注我的Github博客,也算是對(duì)我的一點(diǎn)鼓勵(lì),畢竟寫東西沒(méi)法獲得變現(xiàn),能堅(jiān)持下去也是靠的是自己的熱情和大家的鼓勵(lì)。    許久已經(jīng)沒(méi)有寫東西了,因?yàn)殡s七雜八的原因最近一直沒(méi)有抽出時(shí)間來(lái)把寫作堅(jiān)持下來(lái),感覺(jué)和跑步一...

    liuchengxu 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<