国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

C++從入門到精通 第九章(繼承和多態(tài))【下】

這篇具有很好參考價值的文章主要介紹了C++從入門到精通 第九章(繼承和多態(tài))【下】。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

五、虛函數(shù)與多態(tài)性

1、多態(tài)性的概念

(1)一個面向?qū)ο蟮南到y(tǒng)常常要求一組具有相同基本語義的方法能在同一接口下為不同的對象服務(wù),這就是多態(tài)性。

(2)在C++中,多態(tài)性可分為編譯時的多態(tài)性(靜態(tài)多態(tài))和運行時的多態(tài)性(動態(tài)多態(tài)),編譯時的多態(tài)性是通過函數(shù)重載和模板體現(xiàn)的,運行時的多態(tài)性是通過虛函數(shù)體現(xiàn)的。

(3)靜態(tài)多態(tài)和動態(tài)多態(tài)的區(qū)別:

①靜態(tài)多態(tài)的函數(shù)地址早綁定——編譯階段確定函數(shù)地址。

②動態(tài)多態(tài)的函數(shù)地址晚綁定——運行階段確定函數(shù)地址。

2、虛函數(shù)

(1)在非靜態(tài)成員函數(shù)聲明的前面加上virtual修飾符,即把該函數(shù)聲明為虛函數(shù)。

(2)在派生類中可以重寫從基類繼承下來的虛函數(shù),從而提供該函數(shù)的適用于派生類的專門版本,如果不重寫虛函數(shù),那么繼承下來的虛函數(shù)仍然保持其在基類中的定義,即派生類和基類使用同一函數(shù)版本。(除少數(shù)特殊情況外,在派生類中重寫虛函數(shù)時,函數(shù)名、形參和返回值類型必須保持不變)

(3)虛函數(shù)在派生類中被重寫后,重寫的函數(shù)仍然是虛函數(shù),可以在其派生類中再次被重寫。對于虛函數(shù)的重寫函數(shù),無論是否使用virtual修飾符都是虛函數(shù)(建議加上,避免遺忘它是虛函數(shù))。

(4)對虛函數(shù)的調(diào)用有非多態(tài)調(diào)用和多態(tài)調(diào)用兩種方式:

①非多態(tài)調(diào)用是指不借助指針或引用的直接調(diào)用,它建立在靜態(tài)綁定機制基礎(chǔ)之上,不具備多態(tài)特征)。

多態(tài)調(diào)用是指借助指向基類的指針或引用的調(diào)用,一個基類指針(或引用)可以指向它的派生類對象,而且通過這樣的指針(或引用)調(diào)用虛函數(shù)時,調(diào)用的是該指針(或引用)實際所指向的對象所在類的那個重寫版本。

(5)基類中的實函數(shù)也可以在派生類中改寫,但改寫的函數(shù)仍然是實函數(shù),調(diào)用實函數(shù)時,通過基類指針(或引用)所調(diào)用的也只能是基類的函數(shù)版本,無法調(diào)用到派生類中的改寫函數(shù)。(換句話說,對實函數(shù)的任何形式的調(diào)用都是非多態(tài)的)

(6)舉例:

①例1:

#include<iostream>
using namespace std;

class Animal
{
public:
	int m_Age;
	/*void speak()
	{
		cout << "動物在說話" << endl;
	}*/
	virtual void speak()          //虛函數(shù)
	{
		cout << "動物在說話" << endl;
	}
};
class Cat :public Animal
{
public:
	void speak()
	{
		cout << "小貓在說話" << endl;
	}
};
class Dog :public Animal
{
public:
	void speak()
	{
		cout << "小狗在說話" << endl;
	}
};

//地址早綁定 在編譯階段確定函數(shù)地址
//如果想讓貓說話,那么這個函數(shù)地址就不能提前綁定,需要在運行階段綁定(地址晚綁定)
void doSpeak(Animal &animal)   //Animal & animal = cat/dog;父類的指針或者引用執(zhí)行與子類對象
{
	animal.speak();   //動態(tài)多態(tài)滿足條件:有繼承關(guān)系;子類重寫父類的虛函數(shù)
	//重寫時,函數(shù)的返回值類型、函數(shù)名、參數(shù)列表都要完全相同
}

void test01()
{
	Cat cat;
	doSpeak(cat);    
	Dog dog;
	doSpeak(dog);
}

int main() {

	test01();

	system("pause");

	return 0;
}

②例2:

#include<iostream>
using namespace std;

class Animal
{
public:
	virtual void speak()
	{
		cout << "動物在說話" << endl;
	}
};
class Cat :public Animal
{
public:
	/*void speak()
	{
		cout << "小貓在說話" << endl;
	}*/
};
class Dog :public Animal
{
public:
	virtual void speak()
	{
		cout << "小狗在說話" << endl;
	}
};

void doSpeak(Animal &animal)   
{
	animal.speak();   
}

void test01()
{
	Cat cat;
	doSpeak(cat);
	Dog dog;
	doSpeak(dog);
}
void test02()
{
	cout << "sizeof Animal=" << sizeof(Animal) << endl;   //虛函數(shù)帶指針vfptr,所以對象占4個字節(jié)
	cout << "sizeof Animal=" << sizeof(Cat) << endl;
	cout << "sizeof Animal=" << sizeof(Dog) << endl;
}

int main() {

	test01();
	test02();

	system("pause");

	return 0;
}

③例3:

#include<iostream>
using namespace std;
#include<string>

class Calculator         //普通寫法
{
public:
	int m_Num1;
	int m_Num2;
	int getResult(string oper)
	{
		if (oper == "+")
		{
			return m_Num1 + m_Num2;
		}
		else if (oper == "-")
		{
			return m_Num1 - m_Num2;
		}
		else if (oper == "*")
		{
			return m_Num1 * m_Num2;
		}
	}
};
class AbstractCalculator    //多態(tài)技術(shù)
{
public:
	int m_Num1;
	int m_Num2;
	virtual int getResult()
	{
		return 0;
	}
};
class AddCalculator :public AbstractCalculator
{
	int getResult()
	{
		return m_Num1 + m_Num2;
	}
};
class SubCalculator :public AbstractCalculator
{
	int getResult()
	{
		return m_Num1 - m_Num2;
	}
};
class MulCalculator :public AbstractCalculator
{
	int getResult()
	{
		return m_Num1 * m_Num2;
	}
};
//開閉原則:對擴展進行開發(fā),對修改進行關(guān)閉
void test01()
{
	Calculator c;
	c.m_Num1 = 10;
	c.m_Num2 = 10;
	cout << c.m_Num1 << "+" << c.m_Num2 << "=" << c.getResult("+") << endl;
	cout << c.m_Num1 << "-" << c.m_Num2 << "=" << c.getResult("-") << endl;
	cout << c.m_Num1 << "*" << c.m_Num2 << "=" << c.getResult("*") << endl;
}
void test02()
{
	AbstractCalculator* abc = new AddCalculator;
	abc->m_Num1 = 100;
	abc->m_Num2 = 100;
	cout << abc->m_Num1 << "+" << abc->m_Num2 << "=" << abc->getResult() << endl;
	delete abc;   //用完計算器后記得銷毀
	abc = new SubCalculator;
	abc->m_Num1 = 100;
	abc->m_Num2 = 100;
	cout << abc->m_Num1 << "-" << abc->m_Num2 << "=" << abc->getResult() << endl;
	delete abc;   //用完計算機后記得銷毀
	abc = new MulCalculator;
	abc->m_Num1 = 100;
	abc->m_Num2 = 100;
	cout << abc->m_Num1 << "*" << abc->m_Num2 << "=" << abc->getResult() << endl;
}

int main() {

	test01();
	test02();

	system("pause");

	return 0;
}

3、純虛函數(shù)和抽象類

(1)為了將一個虛函數(shù)聲明為純虛函數(shù),需要在虛函數(shù)原型的語句結(jié)束符“;”之前加上“=0”。

(2)擁有純虛函數(shù)的類稱為抽象類,抽象類不能用來定義對象。如果一個抽象類的派生類沒有重寫來自其基類的某個純虛函數(shù),則該函數(shù)在派生類中仍然是純虛函數(shù),這就使得該派生類也稱為抽象類,也就是說,一個派生類可以把重寫純虛函數(shù)的任務(wù)進一步轉(zhuǎn)交給它自己的派生類。

(3)可以在將一個函數(shù)聲明為純虛函數(shù)的同時為該函數(shù)提供實現(xiàn)版本,一個函數(shù)是否為純虛函數(shù),取決于其原型的尾部是否為“=0;”,與實現(xiàn)版本的有無沒有關(guān)系。純虛函數(shù)的實現(xiàn)版本通常是不完善的版本,但包含了一些共有操作供各個派生類在重寫函數(shù)中調(diào)用。擁有實現(xiàn)版本的純虛函數(shù)仍然有賴于派生類提供重寫版本。

(4)派生類在重寫一個純虛函數(shù)時可以繼續(xù)將之聲明為純虛函數(shù)。另外,純虛函數(shù)不得聲明為內(nèi)聯(lián)函數(shù)。

(5)舉例:

①例1:

#include<iostream>
using namespace std;

class Base  
{
public:
	int m_Num1;
	int m_Num2;
	virtual int func() = 0;    //純虛函數(shù)
};
class Son :public Base
{
public:
	int func()          //子類必須重寫父類中的純虛函數(shù),否則無法實例化對象
	{
		cout << "func()函數(shù)調(diào)用" << endl;
	}
};

void test01()
{
	//Base b;      對于抽象類,無法實例化對象,即使是在堆區(qū)開辟也不行
	Base * base = new Son;
	base->func();
}

int main() {

	test01();

	system("pause");

	return 0;
}

②例2:

#include<iostream>
using namespace std;

class AbstractDrinking
{
public:
	virtual void zhushui() = 0;
	virtual void chongpao() = 0;
	virtual void daorubeizhong() = 0;
	virtual void jiarufuliao() = 0;
	void makeDrink()
	{
		zhushui();
		chongpao();
		daorubeizhong();
		jiarufuliao();
	}
};
class Coffee :public AbstractDrinking
{
public:
	void zhushui()
	{
		cout << "煮水" << endl;
	}
	virtual void chongpao()         //這里virtual 加不加都行
	{
		cout << "沖泡咖啡" << endl;
	}
	void daorubeizhong()
	{
		cout << "倒入杯中" << endl;
	}
	void jiarufuliao()
	{
		cout << "加糖和牛奶" << endl;
	}
};
class Tea :public AbstractDrinking
{
public:
	void zhushui()          
	{
		cout << "煮水" << endl;
	}
	void chongpao()
	{
		cout << "沖泡茶葉" << endl;
	}
	void daorubeizhong()
	{
		cout << "倒入杯中" << endl;
	}
	void jiarufuliao()
	{
		cout << "加檸檬" << endl;
	}
};
void doWork(AbstractDrinking * abs)
{
	abs->makeDrink() ;
	delete abs;  //做完drink后,釋放new在堆區(qū)開辟出的數(shù)據(jù)
}

void test01()
{
	doWork(new Coffee);
	cout << endl;
	doWork(new Tea);
}

int main() {

	test01();

	system("pause");

	return 0;
}

4、虛析構(gòu)函數(shù)和純虛析構(gòu)函數(shù)

(1)析構(gòu)函數(shù)也可通過virtual修飾而聲明為虛函數(shù)。

(2)只要虛基類的析構(gòu)函數(shù)聲明為虛函數(shù),由它派生的所有派生類的析構(gòu)函數(shù)也一定是虛函數(shù)。

(3)在使用多態(tài)時,如果子類中有屬性開辟到堆區(qū),那么父類指針在釋放時無法調(diào)用到子類的析構(gòu)代碼,為了解決這個問題,需要將父類中的析構(gòu)函數(shù)改為虛析構(gòu)函數(shù)或者純虛析構(gòu)函數(shù)

①虛析構(gòu)函數(shù)或純虛析構(gòu)函數(shù)可達到通過父類指針釋放子類對象的目的。

②如果子類中沒有堆區(qū)數(shù)據(jù),可以不將析構(gòu)函數(shù)寫為虛析構(gòu)函數(shù)或純虛析構(gòu)函數(shù)。

③擁有純虛析構(gòu)函數(shù)(不是虛析構(gòu)函數(shù))的類也屬于抽象類,無法實例化對象。

(4)虛析構(gòu)函數(shù)和純虛析構(gòu)函數(shù)的語法:

virtual ~<類名>( ) ????//虛析構(gòu)函數(shù)的定義(類內(nèi))

{

????????<虛析構(gòu)函數(shù)體>

}

virtual ~<類名>( ) = 0; ?//純虛析構(gòu)函數(shù)的聲明(類內(nèi))

<類名>::~<類名>( ) ???//純虛析構(gòu)函數(shù)的定義(類外)

{

????????<純虛析構(gòu)函數(shù)體>

}

(5)舉例:

①例1:

#include<iostream>
using namespace std;
#include<string>

class Animal
{
public:
	virtual void speak() = 0;   //純虛函數(shù)
	Animal()
	{
		cout << "Animal構(gòu)造函數(shù)調(diào)用" << endl;
	}
	virtual ~Animal()   //父類指針在析構(gòu)的時候不會調(diào)用子類中的析構(gòu)函數(shù),子類可能會發(fā)生內(nèi)存泄漏,所以要給它改成虛析構(gòu)
	{
		cout << "Animal析構(gòu)函數(shù)調(diào)用" << endl;
	}
	//virtual ~Animal() = 0;    純虛析構(gòu)(需要有聲明以及具體實現(xiàn))
};
/*Animal::~Animal()     
{
    cout << "Animal純虛析構(gòu)函數(shù)調(diào)用" << endl;
}*/
class Cat :public Animal
{
public:
	void speak() 
	{
		cout << *m_Name << "小貓在說話" << endl;
	}
	Cat(string name)
	{
		cout << "Cat構(gòu)造函數(shù)調(diào)用" << endl;
		m_Name = new string(name);
	}
	~Cat()
	{
		if (m_Name != NULL)
		{
			cout << "Cat析構(gòu)函數(shù)調(diào)用" << endl;
			delete m_Name;
			m_Name = NULL;
		}
	}
	string *m_Name;
};

void test01()
{
	Animal * animal = new Cat("Tom");
	animal->speak();
	delete animal;      
}

int main() {

	test01();

	system("pause");

	return 0;
}

②例2:文章來源地址http://www.zghlxwxcb.cn/news/detail-832076.html

#include<iostream>
using namespace std;

class CPU
{
public:
	virtual void calculate() = 0;
};
class VideoCard
{
public:
	virtual void display() = 0;
};
class Memory
{
public:
	virtual void storage() = 0;
};
class Computer
{
public:
	Computer(CPU * cpu, VideoCard * card, Memory * memory)
	{
		m_cpu = cpu;
		m_card = card;
		m_memory = memory;
	}
	void work()
	{
		m_cpu->calculate();
		m_card->display();
		m_memory->storage();
	}
	~Computer()         //提供析構(gòu)函數(shù)釋放3個電腦零件
	{
		if (m_cpu != NULL)
		{
			delete m_cpu;
			m_cpu = NULL;
		}
		if (m_card != NULL)
		{
			delete m_card;
			m_card = NULL;
		}
		if (m_memory != NULL)
		{
			delete m_memory;
			m_memory = NULL;
		}
	}
private:
	CPU * m_cpu;
	VideoCard * m_card;
	Memory * m_memory;
};
class IntelCPU :public CPU
{
public:
	void calculate()
	{
		cout << "Inter的CPU開始計算了" << endl;
	}
};
class IntelVideoCard :public VideoCard
{
public:
	void display()
	{
		cout << "Inter的顯卡開始顯示了" << endl;
	}
};
class IntelMemory :public Memory
{
public:
	void storage()
	{
		cout << "Inter的內(nèi)存條開始存儲了" << endl;
	}
};
class LenovoCPU :public CPU
{
public:
	void calculate()
	{
		cout << "Lenovo的CPU開始計算了" << endl;
	}
};
class LenovoVideoCard :public VideoCard
{
public:
	void display()
	{
		cout << "Lenovo的顯卡開始顯示了" << endl;
	}
};
class LenovoMemory :public Memory
{
public:
	void storage()
	{
		cout << "Lenovo的內(nèi)存條開始存儲了" << endl;
	}
};

void test01()
{
	//第一臺電腦零件
	CPU * intelCPU = new IntelCPU;
	VideoCard * intelCard = new IntelVideoCard;
	Memory * intelMemory = new IntelMemory;
	//第一臺電腦
	Computer * c1 = new Computer(intelCPU, intelCard, intelMemory);
	c1->work();
	delete c1;
	cout << endl;
	//第二臺電腦
	Computer * c2 = new Computer(new LenovoCPU, new LenovoVideoCard, new LenovoMemory);
	c2->work();
	delete c2;
	cout << endl;
	//第三臺電腦
	Computer * c3 = new Computer(new LenovoCPU, new IntelVideoCard, new LenovoMemory);
	c3->work();
	delete c3;
	cout << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}

到了這里,關(guān)于C++從入門到精通 第九章(繼承和多態(tài))【下】的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • c、c++、java、python、js對比【面向?qū)ο?、過程;解釋、編譯語言;封裝、繼承、多態(tài)】

    c、c++、java、python、js對比【面向?qū)ο?、過程;解釋、編譯語言;封裝、繼承、多態(tài)】

    目錄 內(nèi)存管理、適用 區(qū)別 C 手動內(nèi)存管理:C語言沒有內(nèi)置的安全檢查機制,容易出現(xiàn)內(nèi)存泄漏、緩沖區(qū)溢出等安全問題。 適用于系統(tǒng)級編程 C++ 手動內(nèi)存管理:C++需要程序員手動管理內(nèi)存,包括分配和釋放內(nèi)存,這可能導(dǎo)致內(nèi)存泄漏和指針錯誤。 適用于游戲引擎和系統(tǒng)級編

    2024年02月08日
    瀏覽(51)
  • 第九章 SpringBoot 自動配置原理 入門

    @SpringBootApplication -- @SpringBootConfiguration -- @EnableAutoConfiguration -- @ComponentScan 1.1 @SpringBootConfiguration @Configuration。代表當(dāng)前是一個配置類 1.2 @ComponentScan 指定掃描哪些,Spring注解; 1.3 @EnableAutoConfiguration @EnableAutoConfiguration -- @AutoConfigurationPackage -- @Import(AutoConfigurationImportSelector.clas

    2024年02月13日
    瀏覽(22)
  • (EasyX入門與實戰(zhàn))第九章 鼠標操作

    (EasyX入門與實戰(zhàn))第九章 鼠標操作

    ?基礎(chǔ)代碼: ? ? ? ? 功能:移動畫點,左鍵畫方塊,右鍵退出。? 輸出: ? 進階編程: 1.jpg: 2.jpg: ? ? ? ? 給鼠標添加標志,按鍵做出響應(yīng)。 輸出: ? ? ? ? 小鳥會根跟隨鼠標的位置移動。 ?

    2024年02月11日
    瀏覽(21)
  • Go語言精修(尚硅谷筆記)第九章

    Go語言精修(尚硅谷筆記)第九章

    map是key-value數(shù)據(jù)結(jié)構(gòu),又稱為字段或者關(guān)聯(lián)數(shù)組。類似其它編程語言的集合,在編程中是經(jīng)常使用到 基本語法 key可以是什么類型 golang中的map,的 key 可以是很多種類型,比如 bool, 數(shù)字,string, 指針,channel, 還可以是只包含前面幾個類型的 接口, 結(jié)構(gòu)體, 數(shù)組 通常 key 為 int 、

    2023年04月08日
    瀏覽(16)
  • 『C語言初階』第九章 -結(jié)構(gòu)體

    『C語言初階』第九章 -結(jié)構(gòu)體

    ?? 博客主頁 : 小羊失眠啦. ?? 系列專欄 : C語言 ??? 每日語錄 : 相信自己,比誰都棒。 ?? 感謝大家點贊??收藏?評論?? 前些天發(fā)現(xiàn)了一個巨牛的人工智能學(xué)習(xí)網(wǎng)站,通俗易懂,風(fēng)趣幽默,忍不住分享一下給大家。點擊跳轉(zhuǎn)到網(wǎng)站。 今天小羊又來給鐵汁們分享關(guān)

    2024年02月12日
    瀏覽(19)
  • C++ Primer (第五版)-第九章 順序容器

    C++ Primer (第五版)-第九章 順序容器

    如何選擇合適的容器 迭代器 容器類型成員 列表初始化 賦值和Swap 容器的大小 關(guān)系運算符 9.3.1向順序容器添加元素 訪問元素 刪除元素 改變?nèi)萜鞔笮?### 容器操作可能使迭代器失效 9.5.2、改變string其他的方法 9.5.3 string搜索操作

    2023年04月17日
    瀏覽(26)
  • 《Opencv3編程入門》學(xué)習(xí)筆記—第九章

    《Opencv3編程入門》學(xué)習(xí)筆記—第九章

    記錄一下在學(xué)習(xí)《Opencv3編程入門》這本書時遇到的問題或重要的知識點。 一、圖像直方圖概述 1、作用: ??在每個興趣點設(shè)置一個有相近特征的直方圖所構(gòu)成的標簽,通過標記幀與幀之間顯著的邊緣、顏色、角度等特征的統(tǒng)計變化,來檢測視頻中場景的變化。 2、概念:

    2024年02月11日
    瀏覽(20)
  • WPF入門到跪下 第九章 MVVM-行為處理

    命令是指特定指令、有明確的執(zhí)行內(nèi)容且具有一定的強制性。 命令VS事件 命令與控件的事件看起來有類似的地方,但是兩者是不同的。 控件的事件觸發(fā)函數(shù)是在對應(yīng)窗體的后臺代碼中進行定義的,仔細查閱窗體的后臺代碼,能發(fā)現(xiàn)這是一個部分類,也就是編譯過后后臺代碼

    2024年02月02日
    瀏覽(23)
  • WPF入門到跪下 第九章 MVVM-跨模塊交互

    在實際開發(fā)過程中,經(jīng)常會遇到多個窗口對象,隨之而來的就是對應(yīng)的多個ViewModel對象,這些對象在一定條件下會發(fā)生相互訪問的情況,例如VM與不同窗口交互、VM與不同VM交互,這些不同模塊對象之間的交互,就是跨模塊交互。 MVVM模式下跨模塊交互解決方案 面對跨模塊交互

    2024年02月02日
    瀏覽(53)
  • WPF入門到跪下 第九章 MVVM-基本數(shù)據(jù)處理

    WPF入門到跪下 第九章 MVVM-基本數(shù)據(jù)處理

    MVVM是Model-View-ViewModel的縮寫。mvvm是一種設(shè)計思想。Model 層代表數(shù)據(jù)模型,也可以在Model中定義數(shù)據(jù)修改和操作的業(yè)務(wù)邏輯;View 代表UI 組件,它負責(zé)將數(shù)據(jù)模型轉(zhuǎn)化成UI展現(xiàn)出來,ViewModel是一個同步View和Model的對象。 在MVVM架構(gòu)下,View和Model之間沒有直接的聯(lián)系,它們通過Vie

    2024年01月21日
    瀏覽(24)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包