一,抽象類
1.純虛函數的概念
純虛函數是在父類中定義了一個只有聲明而沒有實現的函數,即使給出了純虛函數的實現,那么編譯器也會忽略。
2.純虛函數的說明形式
virtual 返回值類型 函數名稱(參數列表) = 0;
3.純虛函數的意義
純虛函數只存在了函數的聲明,而不存在函數的實現,在繼承中為子類提供了一個統一的接口,每一個子類對象都可以去實現它,在多態特性中便會根據需要的子類對象而調用相應的子類業務。
4.抽象類的概念
含有純虛函數的類稱為抽象類。
5.抽象類示例
# include<iostream> using namespace std; /* 動物類 */ class Animal { public: /* 純虛函數 */ virtual void eat() = 0; /* 虛析構函數:保證子類的析構函數被調用正確 */ ~Animal() {}; }; /* 狗類 */ class Dog:public Animal { public: virtual void eat() { cout << "狗吃骨頭..." << endl; } }; /* 貓類 */ class Cat :public Animal { public: virtual void eat() { cout << "貓吃魚..." << endl; } }; /* 抽象類指針做函數返回值 */ Animal * get() { Animal * animal = new Cat; return animal; } /* 抽象類引用作函數參數 */ void set(Animal& animal) { animal.eat(); } int main() { /* 抽象類指針 */ Animal * animal1 = new Dog(); animal1->eat(); delete animal1; /* 抽象類引用 */ Cat cat; Animal& animal2 = cat; animal2.eat(); /* 抽象類指針做函數返回值 */ Animal * animal3 = get(); animal3->eat(); delete animal3; /* 抽象類引用作函數參數 */ Dog dog; set(dog); return 0; }
5.抽象類特點
- 抽象類不允許創建對象。
- 抽象類元素不能作為函數的返回值,不能作為函數的參數。
- 抽象類的指針和引用可以做函數參數,可以做返回值,可以指向子類對象。
- 抽象類的子類必須去實現純虛函數,如果不實現,該類還是抽象類。
6.接口
在Java中存在接口的概念,並且Java中只允許單繼承,但是允許接口的多實現。C++中的多繼承存在二義性詬病,不建議使用,而且C++也沒有提供接口的概念,但是我們可以使用抽象類來模擬接口,因此利用這一特性,我們可以使用抽象類模擬的繼承實現接口的多實現,借用C++的多繼承模擬出來的接口的多實現,即解決了C++多繼承的二義性詬病,又極好的實現了大多數現在面向對象語言的接口的功能。
7.接口的案例
# include<iostream> using namespace std; class Interface { public: virtual void print() = 0; }; class Impl1 :public Interface { public: void print() { cout << "Impl1的實現" << endl; } }; class Impl2 :public Interface { public: void print() { cout << "Impl2的實現" << endl; } }; int main() { Interface * i1 = new Impl1; i1->print(); Interface * i2 = new Impl2; i2->print(); return 0; }
二,C語言實現多態
1.函數的三要素
函數的三要素為:函數名稱,函數參數,函數返回值。
2.函數指針的概念
在C語言中我們可以定義指向函數的指針,被稱為函數指針。函數的名稱是函數的入口地址。
3.函數指針的定義
函數指針的定義格式:函數返回值類型 (* 函數指針名稱)(函數參數列表);
4.函數的回調本質
函數的回調,就是利用了函數的指針實現的。首先我們提前約定一個格式,把函數的參數列表和函數的返回值類型規定好,又因為函數的名稱是函數的入口地址,所以我們在函數指針使用的時候傳入函數的名稱(即函數的入口地址)就可以動態的調用符合約定格式的函數。
5.函數指針及函數的回調示例
# include<iostream> using namespace std; /* 定義加法函數 */ int add(int a, int b) { return a + b; } /* 定義減法函數 */ int sub(int a, int b) { return a - b; } /* 定義回調函數 */ int execFun(int(*fun)(int a, int b),int p_a,int p_b) { return fun(p_a, p_b); } int main() { /* 定義一個函數返回值為int,函數參數有兩個int類型的函數指針 */ int(*fun)(int a, int b); /* 動態使得函數指針指向一個函數 */ fun = add; /* 調用函數指針進行運算 */ int r1 = fun(1, 2); cout << "r1 = " << r1 << endl; /* 回調函數:我們只需要傳遞要調用的函數和要計算的數值即可,回調函數幫我們自動調用並返回結果 */ fun = sub; int r2 = execFun(fun, 100, 200); return 0; }
6.函數回調的意義及多態
函數的回調最大的意義是在於不在同一個文件中,我們可以在一個文件中進行回調函數的約定,在另個文件中書寫具體的函數,當在代碼運行時,我們動態的改變函數指針使其指向不同的調用函數,也就實現了C語言的多態。
