多態(tài)性意味著有多種形式。通常,多態(tài)發(fā)生在類之間存在層級關(guān)系且這些類有繼承關(guān)系的時候。
C++ 多態(tài)性是指不同的對象發(fā)送同一個消息,不同對象對應(yīng)同一消息產(chǎn)生不同行為。
考慮下面的例子,一個基類派生了其他的兩類:
#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);
}
};
// Main function for the program
int main( )
{
Shape *shape;
Rectangle rec(10,7);
Triangle tri(10,5);
// store the address of Rectangle
shape = &rec;
// call rectangle area.
shape->area();
// store the address of Triangle
shape = &tri;
// call triangle area.
shape->area();
return 0;
}
上面的代碼編譯和執(zhí)行時,它產(chǎn)生以下結(jié)果:
Parent class area
Parent class area
輸出結(jié)果不正確的原因是對函數(shù) area()
的調(diào)用被編譯器設(shè)置了一次,即在基類中定義的版本,這被稱為對函數(shù)調(diào)用的靜態(tài)分辨或者靜態(tài)鏈接,靜態(tài)鏈接就是在程序被執(zhí)行之前函數(shù)調(diào)用是確定的。這有時也被稱為早期綁定,因為函數(shù) area()
在編譯程序期間是固定的。
但是現(xiàn)在,讓我們對程序做略微修改,并在 Shape 類中 area()
的聲明之前加關(guān)鍵字 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;
}
};
這輕微的修改后,前面的示例代碼編譯和執(zhí)行時,它會產(chǎn)生以下結(jié)果:
Rectangle class area
Triangle class area
這一次,編譯器關(guān)注的是指針的內(nèi)容而不是它的類型。因此,由于三角形和矩形類對象的地址被存儲在形狀類中,各自的 area()
函數(shù)可以被調(diào)用。
正如你所看到的,每個子類都有一個對 area()
函數(shù)的實現(xiàn)。通常多態(tài)就是這樣使用的。你有不同的類,它們都有一個的相同名字的函數(shù),甚至有相同的參數(shù),但是對這個函數(shù)有不同的實現(xiàn)。
基類中的虛函數(shù)是一個使用關(guān)鍵字 virtual 聲明的函數(shù)。派生類中已經(jīng)對函數(shù)進行定義的情況下,定義一個基類的虛函數(shù),就是要告訴編譯器我們不想對這個函數(shù)進行靜態(tài)鏈接。
我們所希望的是根據(jù)調(diào)用函數(shù)的對象的類型對程序中在任何給定指針中被調(diào)用的函數(shù)的選擇。這種操作被稱為動態(tài)鏈接,或者后期綁定。
可能你想把虛函數(shù)包括在基類中,以便它可以在派生類中根據(jù)該類的對象對函數(shù)進行重新定義,但在許多情況下,在基類中不能對虛函數(shù)給出有意義的實現(xiàn)。
我們可以改變基類中的虛函數(shù) area()
如下:
class Shape {
protected:
int width, height;
public:
Shape( int a=0, int b=0)
{
width = a;
height = b;
}
// pure virtual function
virtual int area() = 0;
};
area() = 0
就是告訴編譯器上面的函數(shù)沒有函數(shù)體。上面的虛函數(shù)就被稱為純虛函數(shù)。