中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

邢臺(tái)網(wǎng)站網(wǎng)頁(yè)設(shè)計(jì)公司江西百度推廣公司

邢臺(tái)網(wǎng)站網(wǎng)頁(yè)設(shè)計(jì)公司,江西百度推廣公司,一個(gè)網(wǎng)站有幾個(gè)域名,政府機(jī)構(gòu)網(wǎng)站建設(shè)方案前言 作者:小蝸牛向前沖 名言:我可以接受失敗,但我不能接受放棄 如果覺的博主的文章還不錯(cuò)的話,還請(qǐng)點(diǎn)贊,收藏,關(guān)注👀支持博主。如果發(fā)現(xiàn)有問(wèn)題的地方歡迎?大家在評(píng)論區(qū)指正。 本期學(xué)習(xí)目標(biāo)&am…

前言

作者小蝸牛向前沖

名言我可以接受失敗,但我不能接受放棄

??如果覺的博主的文章還不錯(cuò)的話,還請(qǐng)點(diǎn)贊,收藏,關(guān)注👀支持博主。如果發(fā)現(xiàn)有問(wèn)題的地方歡迎?大家在評(píng)論區(qū)指正。

本期學(xué)習(xí)目標(biāo):認(rèn)識(shí)什么是多態(tài),?認(rèn)識(shí)抽象類,理解多態(tài)的原理,理解多承和多態(tài)常見的面試問(wèn)題。?

目錄

一、認(rèn)識(shí)多態(tài)

1、什么是多態(tài)

2、虛函數(shù)

3、多態(tài)的定義

4、多態(tài)中虛函數(shù)的二種特殊情況

二、抽象類

1、概念

2、?接口繼承和實(shí)現(xiàn)繼承

三、多態(tài)的原理

1、虛函數(shù)表

2、多態(tài)原理剖析

3、單繼承和多繼承關(guān)系的虛函數(shù)表

四、多態(tài)的其他知識(shí)

1、C++11 override 和 final

2、重載、覆蓋(重寫)、隱藏(重定義)的對(duì)比

3、動(dòng)態(tài)綁定與靜態(tài)綁定

五、分享繼承和多態(tài)常見的面試問(wèn)題


一、認(rèn)識(shí)多態(tài)

1、什么是多態(tài)

多態(tài)的概念:通俗來(lái)說(shuō),就是多種形態(tài),具體點(diǎn)就是去完成某個(gè)行為,當(dāng)不同的對(duì)象去完成時(shí)會(huì)
產(chǎn)生出不同的狀態(tài)。

舉個(gè)例子來(lái)說(shuō):某寶常年到大學(xué)的開學(xué)季就會(huì)舉辦掃描領(lǐng)紅包活動(dòng),但是我們發(fā)現(xiàn)每個(gè)領(lǐng)到的金額都不同,而且相對(duì)來(lái)是非活躍用戶紅包金額更大,這種我們不同角色,分到吧同金額的紅包我們就可以稱為多態(tài)。

2、虛函數(shù)

在認(rèn)識(shí)多態(tài)前,我們首先要認(rèn)識(shí)一一下什么是虛函數(shù):

在類中被關(guān)鍵字virtual修飾的函數(shù)我們就稱為虛函數(shù),就如red_packet函數(shù),在繼承中我用關(guān)鍵字virtual解決的菱形繼承問(wèn)題,這里要注意區(qū)分二則的用法,一個(gè)是在繼承這作用于類,一個(gè)是在多態(tài)中作用于函數(shù)。

class Peson
{virtual void red_packet(){cout << "小額紅包" << endl;}
protected:string _name;int _age;
};

3、多態(tài)的定義

那么在繼承中要構(gòu)成多態(tài)還有兩個(gè)條件:

1. 必須通過(guò)基類的指針或者引用調(diào)用虛函數(shù)
2. 被調(diào)用的函數(shù)必須是虛函數(shù),且派生類必須對(duì)基類的虛函數(shù)進(jìn)行重寫

?虛函數(shù)的重寫(覆蓋):派生類中有一個(gè)跟基類完全相同的虛函數(shù)(即派生類虛函數(shù)與基類虛函數(shù)的
返回值類型、函數(shù)名字、參數(shù)列表完全相同),稱子類的虛函數(shù)重寫了基類的虛函數(shù)。

下面我們來(lái)看一段代碼:

class Person
{
public://虛函數(shù)virtual void red_packet(){cout << "普通紅包" << endl;}
protected:string _name;int _age;
};class  active_people:public Person
{
public:virtual void red_packet(){cout << "小額紅包" << endl;}
};void fun(Peson& p)
{p.red_packet();
}
int main()
{Person p;active_people ap;fun(p);fun(ap);return 0;
}

?

這里我們通過(guò)父類的引用形成了多態(tài)。

特別注意子類函數(shù)可以不加victual,但父類必須加victual才構(gòu)成虛函數(shù)

4、多態(tài)中虛函數(shù)的二種特殊情況

我們都知道,要構(gòu)成多態(tài)就用就要滿足構(gòu)成多態(tài)的二個(gè)條件:其中被調(diào)用的函數(shù)必須是虛函數(shù),也就是說(shuō)必須加是virtual。

但是存在二種特殊情況也構(gòu)成多態(tài):

析構(gòu)函數(shù)(函數(shù)名字不同構(gòu)成的重寫)

class Person
{
public:~Person(){cout << " Person delete" << endl;delete[]_p;}
protected:int* _p = new int[10];};class  active_people:public Person
{
public:~active_people(){cout << " active_people delete" << endl;delete[]_d;}
protected:int* _d = new int[15];};int main()
{Person p;active_people ap;return 0;
}

通過(guò)這段代碼我們可以看出,父子類在調(diào)用析構(gòu)函數(shù)的時(shí)候,是先調(diào)用子類的析構(gòu)函數(shù),子類的析構(gòu)函數(shù)調(diào)用完成后,子類會(huì)自動(dòng)調(diào)用父類的析構(gòu)函數(shù)。?

但是如果我對(duì)代碼進(jìn)行一下更改:

int main()
{Person* ptr1 = new Person;Person* ptr2 = new active_people;delete ptr1;delete ptr2;return 0;
}

這里我們發(fā)現(xiàn)子類并沒有被析構(gòu)掉。為什么呢?

這就得提一下delete的特性:

1:使用指針調(diào)用析構(gòu)

2:operator delete(ptr)?

也就是說(shuō)這時(shí)候是一個(gè)普通調(diào)用?(是什么類型就調(diào)用什么用的析構(gòu)函數(shù)),所以才只會(huì)調(diào)用父類的析構(gòu),但這樣的行為不是我們期望的(存在內(nèi)存泄露),其實(shí),我們期望應(yīng)該是一個(gè)多態(tài)調(diào)用,指向父類調(diào)用父類的析構(gòu),指向子類調(diào)用子類的析構(gòu)函數(shù),只要我們?cè)诟割惖奈鰳?gòu)函數(shù)上加上virtual就可以解決這個(gè)問(wèn)題了。

virtual ~Person()
{cout << " Person delete" << endl;delete[]_p;
}

就是為了讓父類的析構(gòu)函數(shù)為虛函數(shù):?

如果基類的析構(gòu)函數(shù)為虛函數(shù),此時(shí)派生類析構(gòu)函數(shù)只要定義,無(wú)論是否加virtual關(guān)鍵字,
都與基類的析構(gòu)函數(shù)構(gòu)成重寫,雖然基類與派生類析構(gòu)函數(shù)名字不同。雖然函數(shù)名不相同,
看起來(lái)違背了重寫的規(guī)則,其實(shí)不然,這里可以理解為編譯器對(duì)析構(gòu)函數(shù)的名稱做了特殊處
理,編譯后析構(gòu)函數(shù)的名稱統(tǒng)一處理成destructor。

協(xié)變(基類與派生類虛函數(shù)返回值類型不同

派生類重寫基類虛函數(shù)時(shí),與基類虛函數(shù)返回值類型不同。即基類虛函數(shù)返回基類對(duì)象的指
針或者引用,派生類虛函數(shù)返回派生類對(duì)象的指針或者引用時(shí),稱為協(xié)變。

舉例:

class A
{};class B : public A
{};
class Person
{
public:virtual A* red_packet(){cout << "普通紅包" << endl;return nullptr;}
};class  active_people :public Person
{
public:virtual B* red_packet(){cout << "小額紅包" << endl;return nullptr;}
};void fun(Person& p)
{p.red_packet();
}
int main()
{Person p;active_people ap;fun(p);fun(ap);return 0;
}

?這里我們只要簡(jiǎn)單知道在協(xié)變這要求:三同中,返回值可以不同,但是要求返回值必須是一個(gè)父子類關(guān)系的指針或者引用

二、抽象類

1、概念

在虛函數(shù)的后面寫上 =0 ,則這個(gè)函數(shù)為純虛函數(shù)。包含純虛函數(shù)的類叫做抽象類(也叫接口
類)。

抽象類不能實(shí)例化出對(duì)象。派生類繼承后也不能實(shí)例化出對(duì)象,只有重寫純虛函數(shù),派生
類才能實(shí)例化出對(duì)象。純虛函數(shù)規(guī)范了派生類必須重寫,另外純虛函數(shù)更體現(xiàn)出了接口繼承。

那這有什么用呢?

其實(shí)就是強(qiáng)制我們重寫子類的虛函數(shù)

2、?接口繼承和實(shí)現(xiàn)繼承

普通函數(shù)的繼承是一種實(shí)現(xiàn)繼承,派生類繼承了基類函數(shù),可以使用函數(shù),繼承的是函數(shù)的實(shí)
現(xiàn)。

虛函數(shù)的繼承是一種接口繼承,派生類繼承的是基類虛函數(shù)的接口,目的是為了重寫,達(dá)成
多態(tài),繼承的是接口。所以如果不實(shí)現(xiàn)多態(tài),不要把函數(shù)定義成虛函數(shù)。

三、多態(tài)的原理

1、虛函數(shù)表

在了解虛函數(shù)表前,我們先來(lái)看一道筆試題

class Base
{
public:virtual void Func1(){cout << "Base::Func1()" << endl;}virtual void Func2(){cout << "Base::Func2()" << endl;}void Func3(){cout << "Base::Func3()" << endl;}private:int _b = 1;char _ch;
};

我想不少同學(xué)會(huì)認(rèn)為是8,可能認(rèn)為?成員函數(shù)存放在公共的代碼段,我們就只要計(jì)算成員變量大小就可以了,根據(jù)內(nèi)存對(duì)齊就可以得到大小為8個(gè)字節(jié)。

但真的是這樣嗎?

我們打印出類的大小:

cout << sizeof(Base) << endl;

為什么是16個(gè)字節(jié)呢?

int main()
{Base b;cout << sizeof(b) << endl;
}

這時(shí)我們進(jìn)行調(diào)試打開監(jiān)視窗口?

發(fā)現(xiàn)b對(duì)象中存放了_vfptr的東西,這又是什么呢?

其實(shí)是一個(gè)指針, 對(duì)象中的這個(gè)指針我們叫做虛函數(shù)表指針(v代表virtual,f代表function)。一個(gè)含有虛函數(shù)的類中都至少都有一個(gè)虛函數(shù)表指針,因?yàn)?strong>虛函數(shù)的地址要被放到虛函數(shù)表中,虛函數(shù)表也簡(jiǎn)稱虛表。

所以說(shuō)根據(jù)內(nèi)存對(duì)其很容易得到類的大小為16。

那我們?cè)谒伎家粋€(gè)問(wèn)題虛函數(shù)表到底存放在哪里呢?

下面我們通過(guò)一份代碼大致推斷一下:

int main()
{int a = 0;printf("棧:%08lxp \n",& a);const char* str = "hello world";printf("代碼段 / 常量區(qū):%08lxp \n", str);static int b = 0;printf("靜態(tài)區(qū)/數(shù)據(jù)段: %08lxp\n", &b);//取類這前4個(gè)字節(jié)的地址,也就是虛表地址Base be;printf("虛表: %08lxp\n", *((int*)&be));}

通過(guò)打印我們發(fā)現(xiàn)虛表位于代碼段/常量區(qū)中。?

class Base
{
public://父類函數(shù)virtual void Func1(){cout << "Base::Func1()" << endl;}//父類虛函數(shù)virtual void Func2(){cout << "Base::Func2()" << endl;}//父類非虛函數(shù)void Func3(){cout << "Base::Func3()" << endl;}private:int _b = 1;char _ch;
};class Derive : public Base
{
public://子類重寫的虛函數(shù)virtual void Func1(){cout << "Derive::Func1()" << endl;}//非虛函數(shù),重定義void Func3(){cout << "Derive::Func3()" << endl;}
private:int _d = 2;
};

虛表當(dāng)中存儲(chǔ)的就是虛函數(shù)的地址,因?yàn)楦割惍?dāng)中的Func1和Func2都是虛函數(shù),所以父類對(duì)象b的虛表當(dāng)中存儲(chǔ)的就是虛函數(shù)Func1和Func2的地址。

而子類雖然繼承了父類的虛函數(shù)Func1和Func2,但是子類對(duì)父類的虛函數(shù)Func1進(jìn)行了重寫,因此,子類對(duì)象d的虛表當(dāng)中存儲(chǔ)的是父類的虛函數(shù)Func2的地址和重寫的Func1的地址。這就是為什么虛函數(shù)的重寫也叫做覆蓋,覆蓋就是指虛表中虛函數(shù)地址的覆蓋,重寫是語(yǔ)法的叫法,覆蓋是原理層的叫法。

其次需要注意的是:Func2是虛函數(shù),所以繼承下來(lái)后放進(jìn)了子類的虛表,而Func3是普通成員函數(shù),繼承下來(lái)后不會(huì)放進(jìn)子類的虛表。此外,虛函數(shù)表本質(zhì)是一個(gè)存虛函數(shù)指針的指針數(shù)組,一般情況下會(huì)在這個(gè)數(shù)組最后放一個(gè)nullptr。

那我們不由的思考到底虛表是那個(gè)階段就開始初始化?

  • 其實(shí)虛表指針是在構(gòu)造函數(shù)初始化列表的時(shí)候填入對(duì)象的,虛表是在編譯的時(shí)候就生成了。
  • 虛表里面存放是虛函數(shù)地址,同普通函數(shù)一樣編譯完成就放在代碼段這
  • 一個(gè)類這所有的虛函數(shù),都會(huì)放在虛表這。
  • 子類會(huì)將父類的虛表拷貝一份,然后用重寫的虛函數(shù)地址覆蓋到原來(lái)虛表中的函數(shù)地址因此虛函數(shù)的重寫,也叫虛函數(shù)的覆蓋。

2、多態(tài)原理剖析

前面我們說(shuō)了那么多,但是虛表是如何實(shí)現(xiàn)多態(tài)的呢?

class Person {
public://父類虛函數(shù)virtual void BuyTicket() { cout << "買票-全價(jià)" << endl; }
};
class Student : public Person {
public:virtual void BuyTicket() { cout << "買票-半價(jià)" << endl; }
};
void Func(Person* p)
{//通過(guò)調(diào)用父類的引用/指針,指向父類調(diào)用父類,指向子類調(diào)用子類p->BuyTicket();
}
int main()
{Person Mike;Student Johnson;Person* p1 = &Mike;Person* p2 = &Johnson;Func(p1);Func(p2);return 0;
}
  • ?p1指針指向Mike對(duì)象,當(dāng)我們調(diào)用Func函數(shù),且將p1傳給Func時(shí),p1->BuyTicket在mike的虛表中找到虛函數(shù)是Person::BuyTicket。
  • p2指針指向johnson對(duì)象時(shí)p2->BuyTicket在johson的虛表中找到虛函數(shù)是Student::BuyTicket.
  • ?這樣就實(shí)現(xiàn)出了不同對(duì)象去完成同一行為時(shí),展現(xiàn)出不同的形態(tài)

?我們都知道達(dá)到多態(tài),有兩個(gè)條件,一個(gè)是虛函數(shù)覆蓋,一個(gè)是對(duì)象的指針或引用調(diào)
用虛函數(shù),
但這是為什么呢?下面我們通過(guò)反匯編了解一下。

void Func(Person* p)
{
p->BuyTicket();
}
int main()
{
Person mike;
Func(&mike);
mike.BuyTicket();
return 0;
}
// 以下匯編代碼中跟你這個(gè)問(wèn)題不相關(guān)的都被去掉了
void Func(Person* p)
{
...
p->BuyTicket();
// p中存的是mike對(duì)象的指針,將p移動(dòng)到eax中
001940DE mov eax,dword ptr [p]
// [eax]就是取eax值指向的內(nèi)容,這里相當(dāng)于把mike對(duì)象頭4個(gè)字節(jié)(虛表指針)移動(dòng)到了edx
001940E1 mov edx,dword ptr [eax]
// [edx]就是取edx值指向的內(nèi)容,這里相當(dāng)于把虛表中的頭4字節(jié)存的虛函數(shù)指針移動(dòng)到了eax
00B823EE mov eax,dword ptr [edx]
// call eax中存虛函數(shù)的指針。這里可以看出滿足多態(tài)的調(diào)用,不是在編譯時(shí)確定的,是運(yùn)行起來(lái)
以后到對(duì)象的中取找的。
001940EA call eax
00頭1940EC cmp esi,esp
}
int main()
{
...
// 首先BuyTicket雖然是虛函數(shù),但是mike是對(duì)象,不滿足多態(tài)的條件,所以這里是普通函數(shù)的調(diào)
用轉(zhuǎn)換成地址時(shí),是在編譯時(shí)已經(jīng)從符號(hào)表確認(rèn)了函數(shù)的地址,直接call 地址
mike.BuyTicket();
00195182 lea ecx,[mike]
00195185 call Person::BuyTicket (01914F6h)
...
}

看出滿足多態(tài)以后的函數(shù)調(diào)用,不是在編譯時(shí)確定的,是運(yùn)行起來(lái)以后到對(duì)象的中取找的。不滿足多態(tài)的函數(shù)調(diào)用時(shí)編譯時(shí)確認(rèn)好的?.

3、單繼承和多繼承關(guān)系的虛函數(shù)表

單繼承的虛函數(shù)表

這里沒什么可以過(guò)多分析,上面我們都是多單繼承虛表的分析,但是我們要注意一個(gè)現(xiàn)象。

class Base
{
public://父類虛函數(shù)virtual void fun1(){cout << "Base::fun1" << endl;}virtual void fun2(){cout << "Base::fun2" << endl;}
private:int a;
};class Derive :public Base
{//重寫的虛函數(shù)virtual void fun1(){cout << "Derive::fun1" << endl;}//虛函數(shù)virtual void fun3(){cout << "Derive::fun3" << endl;}//普通函數(shù)void fun4(){cout << "DERIVE::fun4" << endl;}
private:int b;
};int main()
{Base b;Derive d;return 0;
}

這里雖然從監(jiān)視窗口我們并沒有從虛表中看到fun3虛函數(shù)的地址,但是我們通過(guò)查詢虛表指針的地址,因?yàn)?strong>虛表本質(zhì)是一個(gè)函數(shù)指針數(shù)組,我們可以發(fā)現(xiàn)fun3函數(shù)的地址是存在的,也就說(shuō)明,只要是虛函數(shù)就會(huì)進(jìn)虛表,但是vs編譯器可能會(huì)對(duì)非重寫的虛函數(shù)優(yōu)化,從而在監(jiān)視窗口中我們不能發(fā)現(xiàn)他。

為了更好的驗(yàn)證,我們對(duì)多繼承關(guān)系的虛函數(shù)表的討論,我們寫一個(gè)函數(shù)來(lái)打印虛函數(shù)的地址:

//為函數(shù)指針數(shù)組重新取個(gè)名字
// 寫法1函數(shù)指針數(shù)組
//void PrintVFTbale(VFPtr vft[], int n)
//{
//	for (int i = 0; i < n; ++i)
//	{
//		printf("[%d]:%p\n", i, vft[i]);
//	}
//}
typedef void(*VFPtr)();
//寫法2
void PrintVFTbale(VFPtr vft[])
{for (int i = 0; vft[i] != nullptr; ++i){printf("[%d]:%p->", i, vft[i]);vft[i]();}cout << endl;

?

這里我們要注意,要想打印虛表,就要取類這前4個(gè)字節(jié)(32位平臺(tái))/前8個(gè)字節(jié)(64位平臺(tái)),?

我們上面的取法是通用的,(void*)在32位平臺(tái)4個(gè)字節(jié),64位平臺(tái)8個(gè)字節(jié)。而我們*(void**)就自然的找到了void*從而在不同平臺(tái)上形成自適應(yīng)。

多繼承虛表函數(shù)(在vs2013上測(cè)試)

class Base1 {
public:virtual void func1() { cout << "Base1::func1" << endl; }virtual void func2() { cout << "Base1::func2" << endl; }
private:int b1;
};class Base2 {
public:virtual void func1() { cout << "Base2::func1" << endl; }virtual void func2() { cout << "Base2::func2" << endl; }
private:int b2;
};class Derive : public Base1, public Base2 {
public://父類重寫了func1virtual void func1() { cout << "Derive::func1" << endl; }virtual void func3() { cout << "Derive::func3" << endl; }
private:int d1;
};// 函數(shù)指針數(shù)組
typedef void(*VFPtr)();
void PrintVFTbale(VFPtr vft[])
{for (int i = 0; vft[i] != nullptr; ++i){printf("[%d]:%p->", i, vft[i]);vft[i]();}cout << endl;
}int main()
{Base1 b1;Base2 b2;PrintVFTbale((VFPtr*)(*(void**)&b1));PrintVFTbale((VFPtr*)(*(void**)&b2));Derive d;PrintVFTbale((VFPtr*)(*(void**)&d));//打印父類的第二張?zhí)摫?   寫法1//PrintVFTbale((VFPtr*)(*(void**)((char*)&d+sizeof(Base1))));//寫法2Base2* ptr2 = &d;PrintVFTbale((VFPtr*)(*(void**)ptr2));return 0;
}

  • ?base1h和base2都有一張?zhí)摫?#xff0c;都被Derive繼承(有二張?zhí)摫?,但是沒有被重寫的func3通常是放在第一張?zhí)摫碇械摹?/li>
  • 我們?cè)谡腋割惖牡诙執(zhí)摫淼臅r(shí)候,可以通過(guò)字節(jié)偏遠(yuǎn)的方法找到,也可以直接用?? ?Base2* ptr2 = &d;切片的方式自動(dòng)偏移。
  • 這里我們打印虛函數(shù)地址結(jié)束調(diào)條件是最后一個(gè)元素為nullptr,但是這種情況在大部分情況下是適應(yīng)的,要注意的是,虛表的具體實(shí)現(xiàn)方式可能因編譯器而異,不同的編譯器可能會(huì)有不同的實(shí)現(xiàn)細(xì)節(jié)。因此,在特定的編譯器和環(huán)境中,虛表的最后一個(gè)元素是否為nullptr可能會(huì)有所不同。但根據(jù)常見的編譯器實(shí)現(xiàn),將最后一個(gè)元素設(shè)為nullptr是一種常見的做法。

四、多態(tài)的其他知識(shí)

1、C++11 override 和 final

在學(xué)習(xí)override和final時(shí),我們先思考一個(gè)問(wèn)題如何實(shí)現(xiàn)一個(gè)不能被繼承的類:

方法1:將構(gòu)造函數(shù)私有(c++98)

class A
{
private:A(){}
};class B : public A
{};

這時(shí)候因?yàn)閷?duì)象對(duì)無(wú)法建立,自然就無(wú)法被繼承

方法2 類定義的時(shí)候加final

這時(shí)候我們稱類為最終類,類不能被繼承。

class A final
{};

其實(shí)final還有一個(gè)功能修飾函數(shù),這該函數(shù)就不能被重寫?

?override: 檢查派生類虛函數(shù)是否重寫了基類某個(gè)虛函數(shù),如果沒有重寫編譯報(bào)錯(cuò)。

2、重載、覆蓋(重寫)、隱藏(重定義)的對(duì)比

重載

二個(gè)函數(shù)在同一個(gè)作用域

函數(shù)名相同/參數(shù)不同

重定義(隱藏)

二個(gè)函數(shù)分別在父類和子類的作用域

函數(shù)名相同

二個(gè)父類和子類的同名函數(shù)不構(gòu)成重寫就是重定義

重寫(覆蓋)

二個(gè)函數(shù)分別在父類和子類的作用域

函數(shù)名/參數(shù)/返回值必須相同(協(xié)變除外)

二個(gè)函數(shù)必須是虛函數(shù)

3、動(dòng)態(tài)綁定與靜態(tài)綁定

  • 靜態(tài)綁定又稱為前期綁定(早綁定),在程序編譯期間確定了程序的行為,也稱為靜態(tài)多態(tài),比如:函數(shù)重載.
  • 動(dòng)態(tài)綁定又稱后期綁定(晚綁定),是在程序運(yùn)行期間,根據(jù)具體拿到的類型確定程序的具體行為,調(diào)用具體的函數(shù),也稱為動(dòng)態(tài)多態(tài)。

五、分享繼承和多態(tài)常見的面試問(wèn)題

1. 什么是多態(tài)

它指的是同一種操作或接口可以被不同類型的對(duì)象以不同的方式實(shí)現(xiàn)和處理的能力。具體來(lái)說(shuō),多態(tài)性使得我們可以使用基類(父類)的指針或引用來(lái)引用子類(派生類)的對(duì)象,并且根據(jù)具體的對(duì)象類型執(zhí)行對(duì)應(yīng)的方法或操作。

多態(tài)有兩種表現(xiàn)形式:靜態(tài)多態(tài)(編譯時(shí)多態(tài))和動(dòng)態(tài)多態(tài)(運(yùn)行時(shí)多態(tài))。

  1. 靜態(tài)多態(tài):通過(guò)函數(shù)重載和運(yùn)算符重載實(shí)現(xiàn),編譯器在編譯階段根據(jù)參數(shù)的靜態(tài)類型決定調(diào)用哪個(gè)函數(shù)或操作符。

  2. 動(dòng)態(tài)多態(tài):通過(guò)虛函數(shù)和基類指針/引用實(shí)現(xiàn),運(yùn)行時(shí)根據(jù)對(duì)象的動(dòng)態(tài)類型來(lái)確定調(diào)用哪個(gè)函數(shù)。即使使用基類指針或引用,也能夠在運(yùn)行時(shí)確定實(shí)際調(diào)用的是子類的方法。

2. 什么是重載、重寫(覆蓋)、重定義(隱藏)?

重載:同一作用域內(nèi),函數(shù)名相同參數(shù)不同
重寫:子類和父類的虛函數(shù),名稱、返回值、參數(shù)都相同,稱子類重寫了父類的虛函數(shù)
重定義:子類和父類的函數(shù)名相同,稱子類隱藏了父類的某個(gè)函數(shù)。

3. 多態(tài)的實(shí)現(xiàn)原理?

父類和子類之中保存的虛表指針是不一樣的,通過(guò)傳入指針或者引用(本質(zhì)也是指針)確定去子類還是父類之中去尋找虛表指針,最后達(dá)到調(diào)用不同虛函數(shù)的目的。?

4. inline函數(shù)可以是虛函數(shù)嗎

?可以,不過(guò)編譯器就忽略inline屬性,這個(gè)函數(shù)就不再是inline,因?yàn)樘摵瘮?shù)要放到虛表中去,如果不構(gòu)成多態(tài)直接調(diào)用,則內(nèi)聯(lián)展開。在類里面定義的函數(shù)默認(rèn)內(nèi)聯(lián)。

5. 靜態(tài)成員可以是虛函數(shù)嗎

?不能,因?yàn)殪o態(tài)成員函數(shù)沒有this指針,使用類型::成員函數(shù)的調(diào)用方式無(wú)法訪問(wèn)虛函數(shù)表,所以靜態(tài)成員函數(shù)無(wú)法放進(jìn)虛函數(shù)表。

6. 構(gòu)造函數(shù)可以是虛函數(shù)嗎

?不能,因?yàn)閷?duì)象中的虛函數(shù)表指針是在構(gòu)造函數(shù)初始化列表階段才初始化的。

?7. 析構(gòu)函數(shù)可以是虛函數(shù)嗎?什么場(chǎng)景下析構(gòu)函數(shù)是虛函數(shù)?

?可以,并且最好把基類的析構(gòu)函數(shù)定義成虛函數(shù)。

通過(guò)基類指針或引用來(lái)管理派生類對(duì)象。如果基類中的析構(gòu)函數(shù)不是虛函數(shù),當(dāng)通過(guò)基類指針或引用刪除派生類對(duì)象時(shí),可能只會(huì)調(diào)用到基類的析構(gòu)函數(shù),而不會(huì)調(diào)用派生類的析構(gòu)函數(shù),從而導(dǎo)致派生類可能存在資源泄漏或未被正確清理的問(wèn)題

8. 對(duì)象訪問(wèn)普通函數(shù)快還是虛函數(shù)更快?

?先如果是普通對(duì)象,是一樣快的。如果是指針對(duì)象或者是引用對(duì)象,則調(diào)用的普通函數(shù)快,因?yàn)闃?gòu)成多態(tài),運(yùn)行時(shí)調(diào)用虛函數(shù)需要到虛函數(shù)表中去查找。

9. 虛函數(shù)表是在什么階段生成的,存在哪的?

?虛函數(shù)表是在編譯階段就生成的,一般情況下存在代碼段(常量區(qū))的。

10. C++菱形繼承的問(wèn)題?虛繼承的原理??

?菱形虛擬繼承因?yàn)樽宇悓?duì)象當(dāng)中會(huì)有兩份父類的成員,因此會(huì)導(dǎo)致數(shù)據(jù)冗余和二義性的問(wèn)題。
虛繼承對(duì)于相同的虛基類在對(duì)象當(dāng)中只會(huì)存儲(chǔ)一份,若要訪問(wèn)虛基類的成員需要通過(guò)虛基表獲取到偏移量,進(jìn)而找到對(duì)應(yīng)的虛基類成員,從而解決了數(shù)據(jù)冗余和二義性的問(wèn)題。

11.什么是抽象類?抽象類的作用?

在虛函數(shù)的后面寫上 =0 ,則這個(gè)函數(shù)為純虛函數(shù)。包含純虛函數(shù)的類叫做抽象類?。

抽象類強(qiáng)制重寫了虛函數(shù),另外抽象類體現(xiàn)出了接口繼承關(guān)系。

http://www.risenshineclean.com/news/11351.html

相關(guān)文章:

  • 網(wǎng)站開發(fā)設(shè)計(jì)方案拓客團(tuán)隊(duì)怎么聯(lián)系
  • 徐州市城鄉(xiāng)建設(shè)局網(wǎng)站適合seo的建站系統(tǒng)
  • 3d網(wǎng)站制作seo網(wǎng)站推廣軟件
  • 建立自己的網(wǎng)站平臺(tái)需多少錢優(yōu)化系統(tǒng)軟件
  • 網(wǎng)站怎么做才是對(duì)搜索引擎友好百度賬號(hào)客服人工電話
  • 哪個(gè)網(wǎng)站可以做問(wèn)卷調(diào)查中國(guó)網(wǎng)絡(luò)營(yíng)銷公司排名
  • 企業(yè)獨(dú)立官方網(wǎng)站網(wǎng)址怎么做百度搜索官方網(wǎng)站
  • 網(wǎng)站建設(shè)接外包流程圖網(wǎng)站seo平臺(tái)
  • 房地產(chǎn)網(wǎng)站建設(shè)平臺(tái)免費(fèi)p站推廣網(wǎng)站入口
  • 網(wǎng)站開發(fā)廣東seo搜索
  • wordpress 博客 簡(jiǎn)書有必要買優(yōu)化大師會(huì)員嗎
  • 邯鄲網(wǎng)站建設(shè)制作怎么給自己的網(wǎng)站設(shè)置關(guān)鍵詞
  • 做網(wǎng)站開發(fā)需要培訓(xùn)嗎網(wǎng)站市場(chǎng)推廣
  • 南京網(wǎng)站建設(shè)價(jià)位外貿(mào)平臺(tái)有哪些比較好
  • 網(wǎng)站服務(wù)器轉(zhuǎn)移視頻嗎武漢最新疫情
  • wordpress圖片在哪惠州seo代理
  • discuz論壇 整合到網(wǎng)站漯河網(wǎng)站seo
  • 網(wǎng)站 如何備案培訓(xùn)心得體會(huì)800字
  • wordpress訂單推送微信sem與seo
  • 做國(guó)外銷售都上什么網(wǎng)站不付費(fèi)免費(fèi)網(wǎng)站
  • ps做網(wǎng)站頁(yè)面美工班級(jí)優(yōu)化大師官方免費(fèi)下載
  • 維恩圖在線制作網(wǎng)站站長(zhǎng)工具的使用seo綜合查詢運(yùn)營(yíng)
  • 做網(wǎng)站不用服務(wù)器嗎鄭州網(wǎng)站開發(fā)公司
  • 找做報(bào)紙的背景圖去什么網(wǎng)站海外推廣代理商
  • 個(gè)人如何開網(wǎng)站東莞網(wǎng)絡(luò)推廣營(yíng)銷
  • 哪家網(wǎng)站建設(shè)服務(wù)好開發(fā)網(wǎng)站需要多少錢
  • 懷化市優(yōu)化辦電話seo快速排名優(yōu)化公司
  • 東莞建工集團(tuán)知乎推廣優(yōu)化
  • 周口網(wǎng)站制作公司哪家好快速網(wǎng)站seo效果
  • 江蘇 網(wǎng)站 備案黃頁(yè)引流推廣網(wǎng)站入口