真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

C++之多態(tài)(中篇)(最全總結(jié))-創(chuàng)新互聯(lián)

這里接上面C++之多態(tài)(上篇)

成都創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供常德網(wǎng)站建設(shè)、常德做網(wǎng)站、常德網(wǎng)站設(shè)計(jì)、常德網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)與制作、常德企業(yè)網(wǎng)站模板建站服務(wù),10余年常德做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。本篇目錄
  • 4.多態(tài)的原理
    • 4.2 多態(tài)的原理
    • 4.3 C++ 11 override和final
    • 4.4 重載、重寫(覆蓋)、隱藏(重定義)的對比 (函數(shù)之間的關(guān)系)
  • 5.抽象類
    • 5.1概念
    • 5.2接口繼承和實(shí)現(xiàn)繼承
  • 6.單繼承和多繼承關(guān)系的虛函數(shù)表

4.多態(tài)的原理 4.2 多態(tài)的原理

從上面虛函數(shù)的分析中我們已經(jīng)知道了多態(tài)的原理,接下來我們從更深層次去探索多態(tài)。

class Person
{public:
	virtual void BuyTicket()
	{cout<< "買票-全價(jià)"<< endl;
	}
	virtual void Func1(){}
};

class Student :public Person
{public:
	virtual void BuyTicket()
	{cout<< "買票-半價(jià)"<< endl;
	}
	virtual void Func2(){}
};

int main()
{//同一個(gè)類型的對象共用一個(gè)虛表
	Person p1;
	Person p2;

	//vs下,不管是否完成重寫,子類虛表跟父類虛表都不是同一個(gè)
	Student s1;
	Student s2;
	return 0;
}

在這里插入圖片描述
通過上圖我們發(fā)現(xiàn),同一個(gè)類型的對象共用同一個(gè)虛表,vs下,不管是否完成重寫,子類虛表跟父類虛表都不是同一個(gè),除此之外,我們發(fā)現(xiàn),vs的監(jiān)視窗口下,子類自己的虛函數(shù)Func2(), 它是在子類自己的虛函數(shù)表中的,但是vs的監(jiān)視窗口卻沒有顯示出來,下面我們用一段程序?qū)⑵湔故境鰜怼?br />虛表的本質(zhì)是一個(gè)函數(shù)指針數(shù)組
在這里插入圖片描述
在這里插入圖片描述

通過上圖我們發(fā)現(xiàn)對象虛表的地址在它對象的地址處的值取前4個(gè)字節(jié)即可。

class Person
{public:
	virtual void BuyTicket()
	{cout<< "Person::買票-全價(jià)"<< endl;
	}
	virtual void Func1()
	{cout<< "Person::Func1()"<< endl;
	}
};

class Student :public Person
{public:
	virtual void BuyTicket()
	{cout<< "Student::買票-半價(jià)"<< endl;
	}
	virtual void Func2()
	{cout<< "Student::Func2()"<< endl;
	}
};

typedef void(*VFPTR)();

//void PrintVFTable(VFPTR table[])//打印虛函數(shù)表
void PrintVFTable(VFPTR* table,size_t n)//打印虛函數(shù)表中的虛函數(shù)地址并且調(diào)用虛函數(shù)
{//for (size_t i = 0; table[i] != nullptr; ++i)
	for (size_t i = 0; i< n; ++i)
	{printf("vft[%d]:%p->", i, table[i]);
		//table[i]();
		VFPTR pf = table[i];//有點(diǎn)類似與強(qiáng)制類型轉(zhuǎn)換
		pf();
	}
	cout<< endl;
}

int main()
{//同一個(gè)類型的對象共用一個(gè)虛表
	Person p1;
	Person p2;

	//vs下,不管是否完成重寫,子類虛表跟父類虛表都不是同一個(gè)
	Student s1;
	Student s2;

	//取對象頭部虛函數(shù)表指針傳遞過去
	//這里的2,3是我們知道對象的虛函數(shù)的個(gè)數(shù)
	PrintVFTable((VFPTR*)*(int*)&p1,2);
	PrintVFTable((VFPTR*)*(int*)&s1,3);
	return 0;
}

在這里插入圖片描述

4.3 C++ 11 override和final

從上面可以看出,C++對函數(shù)的重寫的要求比較嚴(yán)格,但是有些情況下由于疏忽,可能會導(dǎo)致函數(shù)名的字母次序?qū)懛炊鵁o法構(gòu)成重載,而這種錯(cuò)誤在編譯期間是不會報(bào)出來的,只有程序運(yùn)行時(shí)沒有得到預(yù)期結(jié)果才來debug會得不償失,因此:C++ 11提供了override和final這兩個(gè)關(guān)鍵字,可以用來幫助用戶檢測是否重寫。

1.final:修飾虛函數(shù),表示該虛函數(shù)不能被重寫

class Car
{public:
	virtual void Drive()final{}
};

class Benz :public Car
{public:
	virtual void Drive() //error
	{cout<< "Benz-舒適"<< endl;
	}
};

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

class Car
{public:
	virtual void Drive(){}
};

class Benz :public Car
{public:
//檢查子類虛函數(shù)是否完成重寫
	virtual void Drive()override
	{cout<< "Benz-舒適"<< endl;
	}
};
4.4 重載、重寫(覆蓋)、隱藏(重定義)的對比 (函數(shù)之間的關(guān)系)

在這里插入圖片描述

5.抽象類 5.1概念

在虛函數(shù)的后面寫上 =0,則這個(gè)函數(shù)為純虛函數(shù),包含純虛函數(shù)的類叫做抽象類(也叫接口類),抽象類不能實(shí)例化出對象。派生類繼承后也不能實(shí)例化出對象,只有重寫純虛函數(shù),派生類才能實(shí)例化出對象。純虛函數(shù)規(guī)范了派生類必須重寫,另外純虛函數(shù)更體現(xiàn)出了接口繼承。

class Car
{public:
	virtual void Drive() = 0;
};

class Benz :public Car
{public:
	virtual void Drive()
	{cout<< "Benz-舒適"<< endl;
	}
};

class BwM:public Car
{public:
	virtual void Drive()
	{cout<< "BMW-操控"<< endl;
	}
};

int main()
{//Car c;//抽象類不能實(shí)例化對象
	//BwM b;

	Car* ptr = new BwM;
	ptr->Drive();//多態(tài)的體現(xiàn)

	ptr = new Benz;
	ptr->Drive();
	return 0;
}

在這里插入圖片描述

5.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ù)。

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

需要注意的是在單繼承和多繼承關(guān)系中, 下面我們?nèi)リP(guān)注的是派生類對象的虛表模型,因?yàn)榛惖奶摫砟P颓懊嫖覀円呀?jīng)看過了,沒什么需要特別研究的。

class Base1
{public:
	virtual void func1()
	{cout<< "Base1::func1"<< endl;
	}
	virtual void func2()
	{cout<< "Base1::func2"<< endl;
	}
private:
	int b1 = 1;
};

class Base2
{public:
	virtual void func1()
	{cout<< "Base2::func1"<< endl;
	}
	virtual void func2()
	{cout<< "Base2::func2"<< endl;
	}
private:
	int b2 = 2;
};


class Derive :public Base1, public Base2
{public:
	virtual void func1()
	{cout<< "Derive::func1"<< endl;
	}

	virtual void func3()
	{cout<< "Derive::func3"<< endl;
	}
private:
	int d = 3;
};

typedef void(*VFPTR)();

//void PrintVFTable(VFPTR table[])//打印虛函數(shù)表
void PrintVFTable(VFPTR* table,size_t n)//打印虛函數(shù)表中的虛函數(shù)地址并且調(diào)用虛函數(shù)
{//for (size_t i = 0; table[i] != nullptr; ++i)
	for (size_t i = 0; i< n; ++i)
	{printf("vft[%d]:%p->", i, table[i]);
		table[i]();
		VFPTR pf = table[i];//有點(diǎn)類似與強(qiáng)制類型轉(zhuǎn)換
		pf();
	}
	cout<< endl;
}

int main()
{Derive d;

	PrintVFTable((VFPTR*)*(int*)&d,3);//打印Base1虛函數(shù)表
	PrintVFTable((VFPTR*)*(int*)((char*)&d + sizeof(Base1)), 2);//法一:打印Base2虛函數(shù)表
	//法二:打印Base2虛函數(shù)表
	Base2* ptr2 = &d;//切片得到Base2的地址
	PrintVFTable((VFPTR*)(*(int*)ptr2), 2);
	return 0;
}

在這里插入圖片描述
在這里插入圖片描述
更深層次的問題
觀察上圖我們發(fā)現(xiàn)Base1中的func1和Base2中的func1都被Derive進(jìn)行了重寫,它們的內(nèi)容是一樣的,應(yīng)該指向同一份函數(shù),但是它們的地址為什么不一樣呢?

下篇文章我們會揭曉!??!

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧


本文題目:C++之多態(tài)(中篇)(最全總結(jié))-創(chuàng)新互聯(lián)
當(dāng)前網(wǎng)址:http://weahome.cn/article/dedihs.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部