一、虛函數的作用和用法
在使用父類指針指向子類對象時,常常需要調用子類的特有函數。但是由於父類指針的類型限制,不能直接訪問子類中定義的成員函數。可是使用虛函數,就可以讓父類指針調用子類的特有函數了。
虛函數是通過在函數聲明前加上virtual關鍵字表示,並且通常在父類中實現一個虛函數,子類繼承該函數後,如果定義了與父類中函數名、參數、返回值都一致的虛函數,就直接覆蓋了父類的虛函數。這樣,在通過父類指針引用子類對象時,調用虛函數實際執行的是子類中的虛函數。
下面是關於多態的例子:
class Shape{ public: virtual double getArea(){ return -1; //Shape類中的純虛函數 } }; class Circle:public Shape{ int r; public: Circle(int r=0):r(r){}; double getArea(){ return 3.14*r*r; } }; class Rectangle:public Shape{ int w; int h; public: Rectangle(int w=0,int h=0):w(w),h(h){}; double getArea(){ return w*h; } }; int main(){ Shape* shape1 = new Circle(5); //通過父類指針引用子類對象 Shape* shape2 = new Rectangle(3,4); cout<getArea()<<endl; //圓形的面積 cout<getArea()<<endl; //矩形的面積 return 0; }
二、抽象類和純虛函數
虛函數在父類中並沒有實現,但是也可以定義為純虛函數。純虛函數就是只有函數聲明,沒有函數實現的虛函數,它的格式為:virtual 返回類型 函數名() = 0; 抽象類也是一種使用純虛函數的方法。抽象類是無法被實例化的類,只能被繼承來實例化。
在上一個例子中,Shape類中的getArea()函數就是一個純虛函數。這種情況下,Shape類就成為了一個抽象類。如果刪除了圓形和矩形類中的getArea()函數,那麼這兩個類就不能實例化了。
三、動態類型轉換和typeid
有時候在編程過程中,要對父類指針進行轉換成子類指針,這個過程就是動態類型轉換。要想動態類型轉換成功,需要保證父類指向的實際是子類對象。
使用動態類型轉換需要涉及到typeid關鍵字,typeid運算符返回的是一個類型信息的對象,可以使用返回的信息來判斷類型是否匹配。使用基本的類型名判斷在面對多重繼承和虛繼承的情況下會出現問題,所以應該使用type_info來實現動態類型轉換。
下面是關於動態類型轉換的例子:
class Shape{ public: virtual void print(){ cout<<"This is a Shape"<<endl; } }; class Circle:public Shape{ public: void print(){ cout<<"This is a Circle"<print(); Circle* circle = dynamic_cast(shape); if(circle!=NULL){ circle->print(); }else{ cout<<"Null pointer"<<endl; } return 0; }
四、虛基類
在多重繼承的時候,如果某個子類同時繼承了兩個基類,那麼在父類指針轉換成子類指針的時候就會出現問題。這種情況下,虛繼承就可以幫助我們解決問題。虛繼承可以避免每個基類都擁有自己的一份拷貝,有效節省了內存空間,同時也解決了指針轉換的問題。
class A{ public: int a; }; class B:virtual public A{ public: int b; }; class C:virtual public A{ public: int c; }; class D:public B,public C{ public: int d; }; int main(){ D* d = new D(); A* a = d; return 0; }
原創文章,作者:WBYZW,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/330115.html