一.多態
1.理解:
多種形態,多種形式
eg:多個派生類均把基類的方法run重新實現,但是實現的方式不同,體現了多種形式,即為多態
2.分類
(1)編譯時的多態:在編譯過程中確定了同名操作的具體操作對象;
(2)運行時的多態:程序運行過程中才動態地確定操作所針對的對象;
3.聯編
是確定操作的具體對象的過程——把一個標識符名和存儲地址聯系在一起的過程;
聯編:把一條消息和一個對象的方法結合的過程;
根據進行的截斷的不同,可以分為:靜態聯編和動態聯編;
靜態聯編——編譯時多態性——函數重載和運算符重載
動態鏈表——運行時多態性——虛函數
二.函數重載
函數的重載也稱多態函數:使得程序能用同一個名字來訪問一組相關的函數,提高程序的靈活性
函數名相同,但是函數所帶的參數的個數或者數據類型不同;——編譯器根據參數決定調用哪個
1.形式:(1)參數個數或類型有所差別;(2)參數完全相同但屬于不同的類
主要談參數完全相同,但是屬于不同的類;
方法:用對象名區別或者用類名和范圍解析運算符區別
eg:Point pob(15,15)
pob.area()? ? ? ? ?Point::area()
三.虛函數
虛函數實現的是動態的重載;函數調用與函數體之間的聯系是在運行時建立的;動態聯編
1.定義虛函數
在基類中進行,把基類中需要定義為虛函數的成員函數聲明為virtual
基類中的某個成員函數被聲明為虛函數后,就可以在派生類中重新定義。在派生類中重新定義時,其函數原型包括返回類型,函數名,參數個數和類型,參數的順序都必須與基類中的原型完全一致
(指向派生類對象的指針,不能指向私有派生類的對象;當指向公有派生類的對象是只能直接訪問派生類中從基類繼承下來的成員,不能直接訪問公有派生類中定義的成員;)
注意事項:
(1)虛函數的聲明只能出現在類函數原型的聲明中,不能出現在函數實體實現時;
(2)基類中只有保護成員或公有成員才能被聲明為虛函數;
(3)在派生類中重新定義虛函數時,關鍵字virtual可寫可不寫
(4)動態聯編只能通過成員函數來調用或通過指針,引用來訪問虛函數
四。多級繼承和虛函數
多級繼承的虛函數與單繼承的虛函數的調用相同。不同類創建的對象調用的函數是不一樣的;
class Base
{
public:virtual void func(){cout << "Base output" << endl;}
};class Derived1 :public Base
{
public:void func(){cout << "Derived output!" << endl;}
};class Derived2 :public Derived1
{
public:void func(){cout << "Derived2 output!" << endl;}
};void test(Base& b)
{b.func();
}int main()
{Base bObj;Derived1 d1Obj;Derived2 d20bj;//當把基類中的virtual去掉之后,再次運行程序,此時的結果為:只是Base outputtest(bObj);test(d1Obj);test(d20bj);}
五.純虛函數和抽象類
抽象類:包含純虛函數的特殊的類;
建立抽象類是為了多態的使用抽象類的成員函數;
1.純虛函數
在當前的基類中不能為虛函數給出一個有意義的實現時,可將其聲明為純虛函數;純虛函數的實現留給派生類來完成,純虛函數的作用是為派生類提供一個一致的接口;
一般來說:一個抽象類至少有一個純虛函數;
純虛函數的定義:
virtual<函數類型><函數名>(參數表)=0;
virtual void set()=0;//在這里并不表示返回值為0,只是起到形式上的作用,告訴編譯器它是純虛函數,說明在基類中不用定義該函數的函數體;
2.抽象類
包含純虛函數的一種特殊的類,是為了抽象和設計而建立的;并且抽象類是不能創建對象的,?為了強調一個類是抽象類,可以將該類的構造函數聲明為保護的訪問控制權限;
只做子類的共同的操作接口;
抽象類只能用做其他類的基類,不能創建抽象類的對象;不能用作參數類型,函數的返回類型或顯式轉換的類型;
struct IDraw
{virtual void draw() = 0;
};struct ISize
{virtual void getSize(int& w, int& h) = 0;
};class Shape :public ISize, public IDraw
{};class Circle :public Shape
{
private:int m_x, m_y, m_r;
public:Circle(int x, int y, int r);void draw();void getSize(int& w, int& h);
};Circle::Circle(int x, int y, int r) :m_x(x), m_y(y), m_r(r)
{;
}
void Circle::draw()
{cout << "Draw a circle" << endl;
}void Circle::getSize(int& w, int& h)
{w = 2 * m_r;h = 2 * m_r;
}int main()
{Circle circle(0, 0, 123);IDraw* pDraw = &circle;pDraw->draw();ISize* pSize = &circle;int w = 0, h = 0;pSize->getSize(w, h);cout << "Width:" <<w<< endl;cout << "Height:" << h << endl;return 0;
}
通過上述例子:我們可以聲明抽象類的對象指針或者引用,上述:IDraw*pDraw;就可以通過這個指針或者引用來訪問派生類的對象成員;
(在這里說明:C++中,結構體和類幾乎是相同的,主要區別在默認的訪問權限,類默認為私有的,而結構體默認為公有的,除了上述區別之外,;類可以繼承自結構體,結構體也可以繼承自類或者其他結構體,并且結構體中,我們經常定義接口(一組相關的純虛函數),類可以從這些接口結構體繼承,以實現這些接口,就比如上述:IDraw中的draw就為純虛函數)