C++ 繼承
基類 & 派生類
一個類可以派生自多個類,這意味着,它可以從多個基類繼承數據和函數。定義一個派生類,我們使用一個類派生列表來指定基類。類派生列表以一個或多個基類命名,形式如下:
// 派生類 class Rectangle: public Shape { public: int getArea() { return (width * height); } };
多繼承
多繼承即一個子類可以有多個父類,它繼承了多個父類的特性。
C++ 類可以從多個類繼承成員,語法如下:
class <派生類名>:<繼承方式1><基類名1>,<繼承方式2><基類名2>,… { <派生類類體> };
C++ 重載運算符和重載函數
C++ 允許在同一作用域中的某個函數和運算符指定多個定義,分別稱為函數重載和運算符重載。
重載聲明是指一個與之前已經在該作用域內聲明過的函數或方法具有相同名稱的聲明,但是它們的參數列表和定義(實現)不相同。
當您調用一個重載函數或重載運算符時,編譯器通過把您所使用的參數類型與定義中的參數類型進行比較,決定選用最合適的定義。選擇最合適的重載函數或重載運算符的過程,稱為重載決策。
C++ 中的函數重載
在同一個作用域內,可以聲明幾個功能類似的同名函數,但是這些同名函數的形式參數(指參數的個數、類型或者順序)必須不同。您不能僅通過返回類型的不同來重載函數。
#include <iostream> using namespace std; class printData { public: void print(int i) { cout << "Printing int: " << i << endl; } void print(double f) { cout << "Printing float: " << f << endl; } void print(char* c) { cout << "Printing character: " << c << endl; } }; int main(void) { printData pd; // Call print to print integer pd.print(5); // Call print to print float pd.print(500.263); // Call print to print character pd.print("Hello C++"); return 0; }
C++ 中的運算符重載
您可以重定義或重載大部分 C++ 內置的運算符。這樣,您就能使用自定義類型的運算符。
重載的運算符是帶有特殊名稱的函數,函數名是由關鍵字 operator 和其后要重載的運算符符號構成的。與其他函數一樣,重載運算符有一個返回類型和一個參數列表。
Box operator+(const Box&);
// 重載 + 運算符,用於把兩個 Box 對象相加 Box operator+(const Box& b) { Box box; box.length = this->length + b.length; box.breadth = this->breadth + b.breadth; box.height = this->height + b.height; return box; }
C++ 多態
多態按字面的意思就是多種形態。當類之間存在層次結構,並且類之間是通過繼承關聯時,就會用到多態。
C++ 多態意味着調用成員函數時,會根據調用函數的對象的類型來執行不同的函數。
虛函數
虛函數 是在基類中使用關鍵字 virtual 聲明的函數。在派生類中重新定義基類中定義的虛函數時,會告訴編譯器不要靜態鏈接到該函數。
我們想要的是在程序中任意點可以根據所調用的對象類型來選擇調用的函數,這種操作被稱為動態鏈接,或后期綁定。
純虛函數
您可能想要在基類中定義虛函數,以便在派生類中重新定義該函數更好地適用於對象,但是您在基類中又不能對虛函數給出有意義的實現,這個時候就會用到純虛函數。
class Shape { protected: int width, height; public: Shape( int a=0, int b=0) { width = a; height = b; } // pure virtual function virtual int area() = 0; };
= 0 告訴編譯器,函數沒有主體,上面的虛函數是純虛函數。
首先:強調一個概念
定義一個函數為虛函數,不代表函數為不被實現的函數。
定義他為虛函數是為了允許用基類的指針來調用子類的這個函數。
定義一個函數為純虛函數,才代表函數沒有被實現。
定義純虛函數是為了實現一個接口,起到一個規范的作用,規范繼承這個類的程序員必須實現這個函數。
1、簡介假設我們有下面的類層次:
#include <iostream> using namespace std; class A { public: virtual void foo() { cout<<"A::foo() is called"<<endl; } }; class B:public A { public: void foo() { cout<<"B::foo() is called"<<endl; } }; int main(void) { A *a = new B(); a->foo(); // 在這里,a雖然是指向A的指針,但是被調用的函數(foo)卻是B的! return 0; }
B::foo() is called
虛函數只能借助於指針或者引用來達到多態的效果
1、純虛函數聲明如下: virtual void funtion1()=0; 純虛函數一定沒有定義,純虛函數用來規范派生類的行為,即接口。包含純虛函數的類是抽象類,抽象類不能定義實例,但可以聲明指向實現該抽象類的具體類的指針或引用。
2、虛函數聲明如下:virtual ReturnType FunctionName(Parameter) 虛函數必須實現,如果不實現,編譯器將報錯,錯誤提示為:
error LNK****: unresolved external symbol "public: virtual void __thiscall ClassName::virtualFunctionName(void)"
3、對於虛函數來說,父類和子類都有各自的版本。由多態方式調用的時候動態綁定。
4、實現了純虛函數的子類,該純虛函數在子類中就編程了虛函數,子類的子類即孫子類可以覆蓋該虛函數,由多態方式調用的時候動態綁定。
5、虛函數是C++中用於實現多態(polymorphism)的機制。核心理念就是通過基類訪問派生類定義的函數。
6、在有動態分配堆上內存的時候,析構函數必須是虛函數,但沒有必要是純虛的。
7、友元不是成員函數,只有成員函數才可以是虛擬的,因此友元不能是虛擬函數。但可以通過讓友元函數調用虛擬成員函數來解決友元的虛擬問題。
8、析構函數應當是虛函數,將調用相應對象類型的析構函數,因此,如果指針指向的是子類對象,將調用子類的析構函數,然后自動調用基類的析構函數。