---恢復內容開始---
在C++中的一種函數申明被稱之為:純虛函數(pure virtual function).它的申明格式如下
class CShape { public: virtual void Show()=0; };
在什么情況下使用純虛函數(pure vitrual function)?
#include <iostream> #include <cstdlib> #include <cstdio> using namespace std; class abstractcls { public: abstractcls(float speed,int total) //構造函數 { this->speed = speed; this->total = total; } virtual void showmember()= 0; //純虛函數的定義 protected: float speed; int total; }; class car : public abstractcls { public: car(int aird,float speed,int total):abstractcls(speed,total) { this->aird = aird; } virtual void showmember() { cout << speed <<"--------" <<total <<"-----------"<<aird<<endl; } protected: int aird; }; int main() { car b(250,150,4); b.showmember(); return 0; }
下面我們看一道某公司的面試的筆試題(含金量到底有多少??)
#include <iostream> #include <cstdio> using namespace std; class A { public: void foo() { printf("1\n"); } virtual void fuu() { printf("2\n"); } }; class B:public A { public : void foo() { printf("3\n"); } void fuu() { printf("4\n"); } }; int main() { A a; B b; A *p = &a; cout<< "p->foo()---" ; p->foo() ; cout<<"p->fuu()---";p->fuu(); cout <<"-------向上轉型-----------"<<endl; p=&b; cout<<"p->foo()---";p->foo(); cout<<"p->fuu()---";p->fuu(); cout <<"--------向下轉型----------"<<endl; B *ptr =(B *)&a; cout<<"ptr->foo()----";ptr->foo(); cout<<"ptr->fuu()-----";ptr->fuu(); return 0; }
先不要看答案,看自己能否作對??
下面進行詳細分析一下為什么結果是這樣的??你全做對了沒??
第一個p->foo()和p->fuu()都很好理解,本身是基類指針,指向的又是基類對象,調用的都是基類本身的函數,因此輸出結果就是1、2。
第二個輸出結果就是1、4。p->foo()和p->fuu()則是基類指針指向子類對象,正式體現多態的用法,p->foo()由於指針是個基類指針,指向是一個固定偏移量的函數,因此此時指向的就只能是基類的foo()函數的代碼了,因此輸出的結果還是1。而p->fuu()指針是基類指針,指向的fuu是一個虛函數,由於每個虛函數都有一個虛函數列表,此時p調用fuu()並不是直接調用函數,而是通過虛函數列表找到相應的函數的地址,因此根據指向的對象不同,函數地址也將不同,這里將找到對應的子類的fuu()函數的地址,因此輸出的結果也會是子類的結果4.
第三個並不是很理解這種用法,從原理上來解釋,由於B是子類指針,雖然被賦予了基類對象地址,但是ptr->foo()在調用的時候,由於地址偏移量固定,偏移量是子類對象的偏移量,於是即使在指向了一個基類對象的情況下,還是調用到了子類的函數,雖然可能從始到終都沒有子類對象的實例化出現。
第四個:而ptr->fuu()的調用,可能還是因為C++多態性的原因,由於指向的是一個基類對象,通過虛函數列表的引用,找到了基類中foo()函數的地址,因此調用了基類的函數。由此可見多態性的強大,可以適應各種變化,不論指針是基類的還是子類的,都能找到正確的實現方法。
小結:1.有virtual才可能發生多態現象2.不發生多態(無virtual)調用就按原類型調用