c++從入門到精通——多態

多態——概念

多態按字面的意思就是多種形態。當類之間存在層次結構,並且類之間是通過繼承關聯時,就會用到多態。

C++ 多態意味着調用成員函數時,會根據調用函數的對象的類型來執行不同的函數。

下面的實例中,基類 Shape 被派生爲兩個類,如下所示:

#include <iostream> 
using namespace std;
 
class Shape {
   protected:
      int width, height;
   public:
      Shape( int a=0, int b=0)
      {
         width = a;
         height = b;
      }
      int area()
      {
         cout << "Parent class area :" <<endl;
         return 0;
      }
};
class Rectangle: public Shape{
   public:
      Rectangle( int a=0, int b=0):Shape(a, b) { }
      int area ()
      { 
         cout << "Rectangle class area :" <<endl;
         return (width * height); 
      }
};
class Triangle: public Shape{
   public:
      Triangle( int a=0, int b=0):Shape(a, b) { }
      int area ()
      { 
         cout << "Triangle class area :" <<endl;
         return (width * height / 2); 
      }
};
// 程序的主函數
int main( )
{
   Shape *shape;
   Rectangle rec(10,7);
   Triangle  tri(10,5);
 
   // 存儲矩形的地址
   shape = &rec;
   // 調用矩形的求面積函數 area
   shape->area();
 
   // 存儲三角形的地址
   shape = &tri;
   // 調用三角形的求面積函數 area
   shape->area();
   
   return 0;
}

當上面的代碼被編譯和執行時,它會產生下列結果:

Parent class area
Parent class area

導致錯誤輸出的原因是,調用函數 area() 被編譯器設置爲基類中的版本,這就是所謂的靜態多態,或靜態鏈接 - 函數調用在程序執行前就準備好了。有時候這也被稱爲早綁定,因爲 area() 函數在程序編譯期間就已經設置好了。

但現在,讓我們對程序稍作修改,在 Shape 類中,area() 的聲明前放置關鍵字 virtual,如下所示:

class Shape {
   protected:
      int width, height;
   public:
      Shape( int a=0, int b=0)
      {
         width = a;
         height = b;
      }
      virtual int area()
      {
         cout << "Parent class area :" <<endl;
         return 0;
      }
};

修改後,當編譯和執行前面的實例代碼時,它會產生以下結果:

Rectangle class area
Triangle class area

此時,編譯器看的是指針的內容,而不是它的類型。因此,由於 tri 和 rec 類的對象的地址存儲在 *shape 中,所以會調用各自的 area() 函數。

正如您所看到的,每個子類都有一個函數 area() 的獨立實現。這就是多態的一般使用方式。有了多態,您可以有多個不同的類,都帶有同一個名稱但具有不同實現的函數,函數的參數甚至可以是相同的。

例子二

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Animal
{
public:
	virtual void speak()
	{
		cout << "動物在說話" << endl;
	}

	virtual void eat()
	{
		cout << "動物在喫飯" << endl;
	}

};

class Cat :public Animal
{
public:
	void speak()
	{
		cout << "小貓在說話" << endl;
	}

	virtual void eat()
	{
		cout << "小貓在喫魚" << endl;
	}
};

//調用doSpeak ,speak函數的地址早就綁定好了,早綁定,靜態聯編,編譯階段就確定好了地址
//如果想調用貓的speak,不能提前綁定好函數的地址了,所以需要在運行時候再去確定函數地址
//動態聯編,寫法 doSpeak方法改爲虛函數,在父類上聲明虛函數,發生了多態
// 父類的引用或者指針 指向 子類對象
void doSpeak(Animal & animal) //Animal & animal = cat
{
	animal.speak();
}
//如果發生了繼承的關係,編譯器允許進行類型轉換

void test01()
{
	Cat cat;
	doSpeak(cat);

}


void test02()
{
	//cout << sizeof(Animal) << endl;
	//父類指針指向子類對象 多態
	Animal * animal = new Cat;

	//animal->speak();
	// *(int*)*(int*)animal 函數地址
	((void(*)()) (*(int*)*(int*)animal))();

	//  *((int*)*(int*)animal+1)貓喫魚的地址

	((void(*)()) (*((int*)*(int*)animal + 1)))();
}

int main(){

	//test01();

	test02();

	system("pause");
	return EXIT_SUCCESS;
}

測試

test1

小貓在說話

test2

test2說明了多態的原理

小貓在說話
小貓在喫魚
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章