一.繼承和派生
1.概念:
基類(父類):原有的類
派生類(子類):基于基類新建立的類
派生(類的派生):在原有類的基礎上建立新類并且添加新特征的過程
繼承:子類不加修改延續父類的特征
2.單一繼承:子類只有一個基類的繼承
多重繼承:子類擁有多個基類的繼承叫多重繼承
3.使用冒號:
來聲明派生類(子類):
class 子類:public 父類
{
}
上面的聲明表示冒號前面的類(子類)是從冒號后面的類(父類)派生來的,注意父類前面必須使用public來修飾,否則子類對象不能賦值給父類的對象
4.protect修飾符
protect
:只有自身和子類才能訪問,其他類不能訪問
private
:只有自身才能訪問,其他類不能訪問
public
:所有都能訪問
5.子類和父類之間的賦值
class father
{
}
class son:public father
{
}
father a;
son b;
a=b;//可以
b=a;//不行
注意:父類對象不能賦值給子類的對象,這是因為父類的對象成員比子類的對象成員少(子類會增加一些新功能),如果使用子類對象訪問父類的成員,可能出現找不到成員的現象,導致程序出錯。
6.定義子類構造函數
6.1 定義形式:
子類:子類構造函數(參數):父類1(參數),父類2(參數)。。。
{
}
??6.2 構造函數的執行順序:首先調用基類的構造函數,再執行子類的構造函數;釋放對象時,先調用子類的析構函數,再調用父類的析構函數
7.解決程序的兩義性問題:
class A
{
public:
void hello(){cout<<"我是父類A"<<endl;}
}
class B
{
public:
void hello(){cout<<"我是父類B"<<endl;}
}
class C:public A,public B
{
public:
void hello(){cout<<"我是子類C"<<endl;}
}
void main()
{
C c;
c.hello();//輸出“我是子類C”
}
在main函數中調用hello函數,會執行子類C的hello函數,但是如果我想輸出父類A的hello函數,那么就應該使用
作用域操作符::
用它來指定函數屬于那個類:
[cpp]
c.A::hello();
這樣就能輸出“我是父類A”
二.虛函數
如果使用父類的指針來訪問子類的對象成員(父類指針指向子類對象
),那么他能執行到子類的成員嗎?看下面的例子:
class falther
{
public:
void run()
{
cout<<"父親可以跑萬米!"<<endl;
}
}
class son:public falther
{
public:
void run()
{
cout<<"兒子可以跑一百萬米!"<<endl;
}
}
void main()
{
falther *fa=new son();
fa->run();//輸出“父親可以跑萬米”
delete fa;
}
沒錯,使用父指針fa *fa
不能訪問子對象的函數run,那么怎么才能輸出“兒子可以跑一百萬米”呢?
解決辦法:在父類的函數run前面加上關鍵字virtual,也就是父類是虛函數,然后使用系統執行到關鍵字virtual函數的時候,就會自動判斷哪個對象調用了它,然后調用該對象的同名函數,修改程序如下:
class falther
{
public:
virtual void run()
{
cout<<"父親可以跑萬米!"<<endl;
}
}
class son:public falther
{
public:
void run()
{
cout<<"兒子可以跑一百萬米!"<<endl;
}
}
void main()
{
falther *fa=new son();
fa->run();//輸出“兒子可以跑一百萬米”
delete fa;
}
上面使用父指針就可以輸出了“兒子可以跑一百萬米”
三.多態性(c++三大特性:封裝性,繼承性,多態性)
以上面的father和son的例子解釋多態性:
當c++編譯器在編譯的時候,發現
father類的run()函數是虛函數
,這個時候c++就會采用遲綁定 late binding
技術。也就是編譯時不確定具體調用的函數,而是在運行時,根據對象的類型(在程序中,我們傳遞的是son類對象的地址[父類指針指向子類對象]
)來確認是哪個函數,這種能力就叫做c++的多態性
。我們如果沒有在father類的run()前加上vitual關鍵字,c++編譯器在編譯時就確定了哪個函數被調用(調用father中的run),這叫做早期綁定 early binding
。
c++多態性
:在基類的函數前加上virtual關鍵字,在派生類中重寫該函數,運行時就會根據對象的實際類型調用相應的函數。也就是說如果對象類型是派生類,就調用派生類的函數;如果對象類型是基類,就調用基類的函數。
注意:c++的多態性只能通過虛函數來體現。
四.純虛函數和抽象類
[cpp]
class father
{
public:
virtual void run()=0;
}
上面在father類中的虛函數run的函數體=0,這種定義方式就定義一個純虛函數run。
純虛函數
是指被標明為不具體實現的虛函數,它讓類先有一個操作名稱,而沒有操作內容,讓派生類在繼承的時候去具體的實現。凡是含有純虛函數的類就叫做抽象類。抽象類是不能聲明一個對象的,只能作為基類為派生類服務。因為抽象類聲明一個對象,調用其函數是沒有意義的。注意:如果派生類也沒具體的實現抽象類中的純虛函數,那么派生類也會變成一個抽象類,不能實例化對象。