先弄清楚幾個概念:linux
1.C++多態依靠虛函數來實現;
2.凡是類中有帶關鍵字virtual的函數均屬於虛函數,以下:ios
class A { public: void f(){} //--->普通成員函數 public: virtual void f1(void){...} //---> 虛函數 virtual void f2(void)=0; //---> 純虛函數 };
3.虛函數沒有實體部分,即沒有函數體而是等於零,則爲純虛函數。
4.擁有純虛函數的類不能直接定義對象,以下報錯:編程
int main() { A a;//--->錯誤 return 0; }
5.繼承類須要定義純虛函數實體才能定義對象,以下:windows
class B:public A { public: f2(void){ //do something } }; int main() { B b;//--->正確 return 0; }
6.虛函數通常是public成員函數,除非有特別的用處。函數
什麼叫作虛函數表(vtables):
虛函數表是一塊連續的內存,每一個內存單元中記錄一個JMP指令的地址。
虛函數表屬於類而不是具體對象,對不一樣的編譯器其實現有所不一樣,比方
windows虛函數表放在常量段空間中,而linux/unix則放在只讀數據段當中。
(引用別處說法,沒有考證)
什麼叫作虛函數指針(vptrs):
每個由有虛函數生成的對象包含指向虛函數的指針,注意不一樣對象的指this
針地址不一樣,即指向不一樣(這裏不一樣對象是指繼承了具備虛函數基類的子類spa
所生成的對象),正是因爲每一個對象的虛函數指針指向的是本身對應類所實unix
現的函數,所以調用時對應的是子類對象的具體函數實現,從而完成了多態的
實現。指針
#include "stdafx.h" #include<iostream> #include<cmath> #include<ctime> #include<windows.h> using namespace std; enum Color { Red, Black, Yellow, Orange, Brown, White }; class Shape { protected: double xPos; double yPos; Color color; public: Shape(double x=0.0f,double y=0.0f,Color c=White):xPos(x),yPos(y),color(c){} ~Shape(){} protected: public: virtual void setColor(Color)=0; virtual Color getColor()=0; virtual bool drawShape(double,double)=0; virtual void setPosition(double,double)=0; virtual void movePosition(double,double)=0; virtual void erase()=0; virtual void showShape()=0; }; class Circle:public Shape { private: double radius; public: Circle(double r=1.0f):radius(r),Shape(){} ~Circle(){} public: double getRadius(){ return radius; } void setPosition(double x=0.0f,double y=0.0f){ xPos=x; yPos=y; } bool drawShape(double x=0.0f,double y=0.0f){return true;} void movePosition(double x=0.0f,double y=0.0f){} void erase(){} void showShape(){ //畫一個半徑爲radius的圓 for(double yv=this->radius;yv>=-this->radius;yv-=0.1f){ for(double xv=this->radius;xv>=-this->radius;xv-=0.05f){ if(sqrt(pow(xv,2)+pow(yv,2))<=this->radius){ cout<<"*"; } else{ cout<<" "; } } endl(cout); } } Color getColor(){ return Shape::color; } void setColor(Color c=Red){ } }; class Rectangle1:public Shape { private: double length; double width; public: Rectangle1(double l=2.0f,double w=1.0f,double x=0.0f,double y=0.0f):length(l),width(w),Shape(x,y){} ~Rectangle1(){} public: void setPosition(double x=0.0f,double y=0.0f){ xPos=x; yPos=y; } bool drawShape(double x=0.0f,double y=0.0f){ return true;} void movePosition(double x=0.0f,double y=0.0f){ xPos+=x; yPos+=y; } void erase(){} void showShape(){ //畫一個長寬爲xv和yv的長方形 for(double yv=0.0f;yv<=yPos+width;yv+=0.05f){ for(double xv=0.0f;xv<=xPos+length;xv+=0.05f){ if(yv>=yPos&&xv>=xPos)cout<<"*"; else cout<<" "; } endl(cout); } } void setColor(Color c=Red){ } Color getColor(){ return Shape::color; } }; int _tmain(int argc, _TCHAR* argv[]) { Shape* shape; while(true){ for(int i=1;i<=3;i++){ shape=new Circle(i*0.5f); shape->showShape(); //經過虛函數表調用Circle類的showShape函數 Sleep(500); delete shape; shape=new Rectangle1(0.3f*i,0.3f*i,0.3f*i,0.3f*i); shape->showShape(); //經過虛函數表調用Rectangle1類的showShape函數 delete shape; } } }
運行以下:code
結語: 在大型的軟件工程中,類的繼承關係至關複雜龐大,在這樣的狀況下虛函數能夠說 有了極大的用武之地了,一層層的繼承關係,每一個子類對虛函數都會作具體的實現 經過父類指針來調用這些函數能夠在不一樣的代碼段中實現不一樣的功能,極大的方便 了編程,並且讓人感受有點"智能"。 如shape調用Circle類的showShape函數來畫一個圓,而調用Rectangle1類的showShape 函數來畫一個長方形。這是一個簡單的例子,形狀有各類各樣,可是shape指針能夠分別 調用不一樣對象的showShape函數,加上不一樣的參數,即可以畫出形形色色的圖案。 試想,若沒有這種多態機制,那麼必定須要在具體的對象的指針各自調用各自的showShape 函數,這樣即不利於編程,並且失去了父類指針統一調度各個類對象的函數的機制。