1、何為繼承
C++中所謂繼承,就是在一個已存在類的基礎上創建一個新的類,新類獲得已存在類的部分特性(為什么是部分特性,后面會講到)。已存在類被稱為基類(Base Class)或父類(Father Class),新建類被稱為派生類(Derived Class)或子類(Son Class)。
繼承的聲明形式:
class 派生類名:[繼承方式] 基類列表
{
派生類增加的特性;
}
2、分類
繼承在C++中有單繼承與多繼承的分類。
單繼承:派生類有且只有一個基類
多繼承:派生類兩個或兩個以上的基類
文字描述不過癮,給出聲明方法、模型及實例:
①簡單的單繼承聲明方法、模型及實例:
class 派生類名:[繼承方式] 基類名
{
派生類增加的特性;
}
class Base
{
void Fun(){
cout <<
"Base" << endl;}
protected:
int data;
};
class Derived1:
public Base
{
void Fun(){
cout <<
"Derived1" << endl;}
private:
int _data;
};
class Derived2:
public Base
{
void Fun(){
cout <<
"Derived2" << endl;}
private:
int _data;
};
②簡單的多繼承聲明方法、模型及實例:
class 派生類名:[繼承方式] 基類列表
{
派生類增加的特性;
}
class Base1
{
void Fun(){
cout <<
"Base" << endl;}
protected:
int data1;
};
class Base2
{
void Fun(){
cout <<
"Base" << endl;}
protected:
int data2;
};
class Derived:
public Base1,
public Base2
{
void Fun(){
cout <<
"Derived" << endl;}
private:
int _data;
};
3、繼承方式
先來回憶一下繼承的聲明形式:
class 派生類名:[繼承方式] 基類列表
{
派生類增加的特性;
}
其中,繼承方式分為共有(public)、私有(private)、保護(protected)之分,不同的繼承方式會產生不同的繼承效果(class默認繼承方式是私有,struct默認繼承方式是公有,但最好還是顯示給出繼承方式,這樣會使程序更加清晰)。
繼承方式的區別:
public:基類的非私有成員在派生類中的訪問屬性不變,基類的私有屬性在派生類中存在但不可見。
protected:基類的非私有成員都稱為派生類中的保護成員,基類的私有屬性在派生類中存在但不可見。
private:基類的非私有成員都稱為派生類中的私有成員,基類的私有屬性在派生類中存在但不可見。
以上就是為什么說只是基類的部分特性在派生類中可見。
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
class Base
{
public:Base(){}~Base(){}
void ShowBase(){
cout <<
"ShowBase" << endl;
cout <<
"pri = " << pri << endl;
cout <<
"pro = " << pro << endl;
cout <<
"pub = " << pub << endl;}
private:
int pri;
protected:
int pro;
public:
int pub;
};
class Derived :
public Base
{
public:Derived(){}~Derived(){}
void ShowDerived(){
cout <<
"ShowDerived" << endl;
cout <<
"_pri = " << _pri << endl;
cout <<
"_pro = " << _pro << endl;
cout <<
"_pub = " << _pub << endl;}
private:
int _pri;
protected:
int _pro;
public:
int _pub;
};
int main()
{Base b;Derived d;b.ShowBase();d.ShowBase(); d.ShowDerived();
cout <<
sizeof(Base) << endl;
cout <<
sizeof(Derived) << endl;
return 0;
}
輸出結果:
對以上輸出結果分析:
①為什么ShowBase會被調用兩次
ShowBase函數被調用了兩次,是因為在Derived類中,繼承有ShowBase函數,因為該函數在Base類中的屬性是public,而且Derived類是以public方式繼承自Base類的,所以該函數在Derived類中的屬性仍為public,那么它就可以在類外被調用。
②為什么兩個類的大小不同
從輸出結果中很明顯的看到,Base類的大小為12,Derived類的大小為2。Base類的大小為12很好理解,因為它里面只有三個成員變量,且都為int類型,但為什么Derived是24呢,這就要牽扯到了繼承方式特性,不管繼承方式是什么,基類的成員變量的訪問限定符是什么,基類的成員變量在派生類中都是存在的,只是有可見與不可見之分。
當我把繼承方式修改為protected和private時,程序編譯出錯:
這就印證了我們上述的繼承方式的特性,因為protected繼承方式會把Base類中public訪問限定符的BaseShow函數在Derived類中降級為protected訪問限定符,同樣,private繼承方式會把Base類中public訪問限定符的BaseShow函數在Derived類中降級為private訪問限定符,而protected訪問限定符和private訪問限定符修飾的內容在類外是不可見的,強行調用肯定會報錯,所以這兒會出現錯誤。
繼承方式的特性:
①基類的private成員在派生類中是不能被訪問的,如果基類成員不想在類外直接被訪問,但需要在派生類中能訪問,就定義為protected。可以看出保護成員限定符是因繼承才出現的。
②不管是哪種繼承方式,在派生類內部都可以訪問基類的公有成員和保護成員,基類的私有成員存在但是在子類中不可見(不能訪問)。
③使用關鍵字class時默認的繼承方式是private,使用struct時默認的繼承方式是public,不過最好顯示的寫出繼承方式。
4、繼承關系中構造函數和析構函數的調用
先給出一個例子來剖析:
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;class Base
{
public:
Base(){cout <<
"Base()" << endl;}~Base(){cout <<
"~Base()" << endl;}
private:
int pri;
protected:
int pro;
public:
int pub;
};class Derived :
protected Base
{
public:
Derived(){cout <<
"Derived()" << endl;}~Derived(){cout <<
"~Derived()" << endl;}
private:
int _pri;
protected:
int _pro;
public:
int _pub;
};
int main()
{Base b;Derived d;
return 0;
}
可以看到在派生類創建對象時,是先調用基類的構造函數,然后在代用自己的構造函數,對于析構函數就很好解釋了,可以理解為棧的特性,先進后出。
5、繼承關系的作用域
在C++的繼承體系中,基類和派生類是屬于兩個不同作用域。當基類和派生類中有同名成員時,派生類成員將屏蔽基類對成員的直接訪問(在派生類成員函數中,可以使用 基類名::基類成員來訪問基類的同名成員),這就是所謂的同名隱藏,在派生類中的同名成員稱為對基類同名成員的重定義。當然,實際中在繼承體系里面最好不要定義同名的成員。
注意:因為基類和派生類是屬于兩個不同作用域,所以兩個類中的同名函數不會構成函數重載。
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
class Base
{
public:Base(
int _pub =
0,
int _pri =
1,
int _pro =
2): pub(_pub), pri(_pri), pro(_pro){}~Base(){}
void Display(){
cout <<
"Base::Display" << endl;
cout <<
"pub = " << pub << endl;
cout <<
"pri = " << pri << endl;
cout <<
"pro = " << pro << endl;}
public:
int pub;
private:
int pri;
protected:
int pro;
};
class Derived:
public Base
{
public:Derived(
int _pub =
0,
int _pri =
1,
int _pro =
2): pub(_pub), pri(_pri), pro(_pro){}~Derived(){}
void Display(){
cout <<
"Derived::Display" << endl;
cout <<
"pub = " << pub << endl;
cout <<
"pri = " << pri << endl;
cout <<
"pro = " << pro << endl;}
public:
int pub;
private:
int pri;
protected:
int pro;
};
int main()
{Base b(
1,
2,
3);Derived d(
4,
5,
6);b.Display();d.Display();
return 0;
}
根據上面例子的輸出就可以看出來。
6、基類對象與派生類對象的賦值關系
①子類對象可以賦值給父類對象
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
class Base
{
public:Base(
int bpub =
5,
int bpri =
10,
int bpro =
15): pub(bpub), pri(bpri), pro(bpro){}~Base(){}
void Display(){
cout <<
"Base::Display" << endl;
cout <<
"pub = " << pub << endl;
cout <<
"pri = " << pri << endl;
cout <<
"pro = " << pro << endl;}
public:
int pub;
private:
int pri;
protected:
int pro;
};
class Derived:
public Base
{
public:Derived(
int _dpub =
10,
int _dpri =
20,
int _dpro =
30): _pub(_dpub), _pri(_dpri), _pro(_dpro){}~Derived(){}
void Display(){
cout <<
"Derived::Display" << endl;
cout <<
"_pub = " << _pub << endl;
cout <<
"_pri = " << _pri << endl;
cout <<
"_pro = " << _pro << endl;}
public:
int _pub;
private:
int _pri;
protected:
int _pro;
};
int main()
{Base b(
1,
2,
3);Derived d(
4,
5,
6);b = d;b.Display();d.Display();
return 0;
}
輸出結果:
程序可以正常輸出,但有些人可能會奇怪,為什么b里面存的是5、10、15,而不是4、5、6,其實原因很簡單:
②父類對象不能賦值給子類對象
當我把上例中的“b = d;”換成“d = b;”時,編譯器會報錯:
還是像剛才那樣分析:
③父類的指針/引用可以指向子類對象,但是無法使用不存在于基類只存在于派生類的元素。
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
class Base
{
public:Base(
int bpub =
5,
int bpri =
10,
int bpro =
15): pub(bpub), pri(bpri), pro(bpro){}~Base(){}
void Display(){
cout <<
"Base::Display" << endl;
cout <<
"pub = " << pub << endl;
cout <<
"pri = " << pri << endl;
cout <<
"pro = " << pro << endl;}
public:
int pub;
private:
int pri;
protected:
int pro;
};
class Derived:
public Base
{
public:Derived(
int _dpub =
10,
int _dpri =
20,
int _dpro =
30): _pub(_dpub), _pri(_dpri), _pro(_dpro){}~Derived(){}
void Display(){
cout <<
"Derived::Display" << endl;
cout <<
"_pub = " << _pub << endl;
cout <<
"_pri = " << _pri << endl;
cout <<
"_pro = " << _pro << endl;}
public:
int _pub;
private:
int _pri;
protected:
int _pro;
};
int main()
{Derived d(
4,
5,
6);Base *b = &d;b->Display();
return 0;
}
輸出結果:
上分析圖:
④子類的指針/引用不能指向父類對象(可以通過強制類型轉換完成)
我把上例中的
int main()
{Derived d(
4,
5,
6);Base
*b = &d;b->Display();
return 0;
}
換成
int main()
{Base b(
4,
5,
6);Derived
*d = &b;d->Display();
return 0;
}
程序會報錯:
繼續上圖分析:
7、友元與繼承
友元關系不能繼承,也就是說基類友元不能訪問子類私有和保護成員。
8、繼承與靜態成員
基類定義了static成員,則整個繼承體系里面只有一個這樣的成員。無論派生出多少個子類,都只有一個static成員實例。
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;class Base
{
public:
Base(
int bpub =
5,
int bsta =
0,
int bpri =
10,
int bpro =
15): pub(bpub), pri(bpri), pro(bpro){}~Base(){}
void Display(){cout <<
"Base::Display" << endl;cout <<
"sta = " << sta << endl;}
public:
int pub;
static int sta;
private:
int pri;
protected:
int pro;
};class Derived:
public Base
{
public:
Derived(
int _dpub =
10,
int _dpri =
20,
int _dpro =
30): _pub(_dpub), _pri(_dpri), _pro(_dpro){}~Derived(){}
void Display(){cout <<
"Derived::Display" << endl;cout <<
"sta = " << sta << endl;}
public:
int _pub;
private:
int _pri;
protected:
int _pro;
};
int Base::sta =
10;
int main()
{Base b;Derived d;b.Display();d.Display();
return 0;
}
可以看到兩次輸出都是10。
總結
以上是生活随笔為你收集整理的初识C++之继承的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。