C++中的多態性

封裝、繼承、多態是C++的三大基本特性。封裝可以隱藏實現細節,使得代碼模塊化;繼承可以擴展已存在的代碼模塊(類);封裝和繼承的目的都是為了"代碼重用",多態則是為了實現另一個目的:接口重用。

多態說的簡單一些就是"相同的調用產生不同的行為"。這句話具體的涵義在下面會通過例子來解釋。

一、虛函數

C++中的多態是通過虛函數來實現的。虛函數的作用是允許子類重新定義父類的成員函數,這種行為稱為覆蓋或者重寫。

(1)如果使用了多態,利用基類的指針指向任意一個子類對象,調用相應的虛函數(可調用到子類重寫的父類中定義的虛函數),從而實現動態綁定。

(2)如果沒有使用虛函數,那麼即使在子類中存在與父類同名的函數,基於指針也只能調用基類的該成員函數,無法調用到子類中被重寫的該成員函數。

下面先看一個例子:

#include <iostream> 
using namespace std;

//基類
class Shape {
protected:
\tint width, height;

public:
\tShape( int a=0, int b=0) {
\t\twidth = a;
\t\theight = b;
\t}

\tint area() {
\t\tcout << "Parent class area :" <<endl>\t\treturn 0;
\t}
};

//子類Rectangle
class Rectangle: public Shape {
public:
\tRectangle( int a=0, int b=0):Shape(a, b) {
\t
\t}
\tint area () {
\t\tcout << "Rectangle class area :" <<endl>\t\treturn (width * height);
\t}
};

//子類Triangle
class Triangle: public Shape {
public:
\tTriangle( int a=0, int b=0):Shape(a, b) {
\t
\t}
\tint area () {
\t\tcout << "Triangle class area :" <<endl>\t\treturn (width * height / 2);
\t}
};

int main( ) {
Shape *shape;
Rectangle rec(10,7);
Triangle tri(10,5);

shape = &rec;
shape->area();

shape = &tri;
shape->area();

return 0;
}/<endl>/<endl>/<endl>/<iostream>

運行結果為:

C++中的多態性

可以看到即使是將指針shape指向不同的子類(Rectangle/Triangle),執行shape->area();調用的仍然還是父類Shape的成員函數area();。並沒有產生上面所說的"多態"的行為。

修改如下:

#include <iostream> 
using namespace std;

//基類
class Shape {
protected:
\tint width, height;

public:
\tShape( int a=0, int b=0) {
\t\twidth = a;
\t\theight = b;
\t}
\t//使用virtual關鍵字指定為虛函數
\tvirtual int area() {
\t\tcout << "Parent class area :" <<endl>\t\treturn 0;
\t}
};

//子類Rectangle
class Rectangle: public Shape {
public:
\tRectangle( int a=0, int b=0):Shape(a, b) {
\t
\t}
\tvirtual int area () {
\t\tcout << "Rectangle class area :" <<endl>\t\treturn (width * height);
\t}
};

//子類Triangle
class Triangle: public Shape {
public:
\tTriangle( int a=0, int b=0):Shape(a, b) {
\t
\t}
\tvirtual int area () {

\t\tcout << "Triangle class area :" <<endl>\t\treturn (width * height / 2);
\t}
};

int main( ) {
Shape *shape;
Rectangle rec(10,7);
Triangle tri(10,5);

shape = &rec;
shape->area();

shape = &tri;
shape->area();

return 0;
}/<endl>/<endl>/<endl>/<iostream>

執行結果如下:

C++中的多態性

相同的調用shape->area();產生了不同的行為,這個現象就是上面所說的多態性。

下面對虛函數給出一個定義:

虛函數是在基類中使用關鍵字virtual聲明的函數。在子類中重寫基類中定義的虛函數時,會告訴編譯器不要靜態鏈接到該函數,而是在程序運行的任何時候根據指針所指向的對象來選擇調用的函數,這種操作被稱為"動態綁定或後期綁定"。

二、純虛函數

  • 純虛函數是在基類中聲明的虛函數,它沒有具體的定義,要求任何派生類都必須重寫純虛函數
  • 包含純虛函數的類稱為抽象類,抽象類不可以進行實例化
  • 定義純虛函數是為了實現一個接口,起到一個規範的作用,它規定繼承這個類的程序員必須要重寫該純虛函數

為什麼需要純虛函數:在很多情況下,基類本身生成對象時不合情理的。比如說:動物作為一個基類可以派生出老虎類、貓類、狗類,但是動物類本身實例化對象就不合常理。因此引入了純虛函數,包含純虛函數的類稱為抽象類,用戶不能創建抽象類的實例,只能創建它的派生類的實例。

#include <iostream>
using namespace std;

class Animal {
protected:
\tstring name_;
public:
\tAnimal(string name) {
\t\tname_ = name;
\t}
\t~Animal() {
\t\t
\t}
//定義純虛函數
\tvirtual void ShowMe() = 0;
};

class Dog: public Animal {
public:
\tDog(string name): Animal(name) {
\t\t
\t}
\t~Dog() {
\t\t
\t}
\tvirtual void ShowMe() {
\t\tcout << "I am a dog and my name is " << name_ << endl;
\t}
};

class Cat: public Animal {
public:
\tCat(string name): Animal(name) {
\t\t
\t}
\t~Cat() {
\t\t
\t}
\tvirtual void ShowMe() {
\t\tcout << "I am a cat and my name is " << name_ << endl;
\t}
};

int main() {
\t//error: 抽象類不可以實例化
\t//Animal* animal = new Animal("動物");\t
\tAnimal* animal;
\tDog* dog = new Dog("阿黃");

\tCat* cat = new Cat("小黑");
\t
\tanimal = dog;
\tanimal->ShowMe();
\t
\tanimal = cat;
\tanimal->ShowMe();
\t
\treturn 0;
}/<iostream>

運行結果如下:

C++中的多態性

今天的內容就到這兒了。如果對我的推|文有興趣,歡迎轉|載分|享。也可以推|薦給朋友關|注哦。只推乾貨,寧缺毋濫。

C++中的多態性


分享到:


相關文章: