一般形式
class class_name:繼承方式 基類名{ code }
繼承方式有三種: public ,protected,private. //java好像都是public繼承。
單繼承
多繼承,多繼承會(huì)很復(fù)雜,所以java,c sharp都采用interface。
類函數(shù):
構(gòu)造函數(shù)
先執(zhí)行父類的構(gòu)造函數(shù),在執(zhí)行子類的構(gòu)造函數(shù)。
一般形式 派生類的構(gòu)造函數(shù)(參數(shù)列表):基類構(gòu)造函數(shù)名(參數(shù)列表}{ code}
析構(gòu)函數(shù)
先構(gòu)造的后析構(gòu),后構(gòu)造的先析構(gòu)。
虛函數(shù)。
避免二義性。但是最后的派生類不僅負(fù)責(zé)對(duì)直接基類初始化,還要對(duì)虛基類初始化。
看code是最有用的,細(xì)節(jié)情況已經(jīng)注釋說(shuō)明。
#include<iostream>
#include<string>
using namespace std;
// 類A
class A {
protected:
string name;
int id;
double da;
private:
double pa; //這個(gè)數(shù)據(jù)繼承后不能被訪問(wèn)
public:
A(string name, int id) {
cout << "A的構(gòu)造函數(shù)執(zhí)行"<<endl;
this->name = name; //this指針
this->id = id;
this->da = da;
}
void setDa(double d) {
da = d;
}
~A() {
cout << "A的析構(gòu)函數(shù)"<<endl;
}
void setId(int id) {
//id是私有數(shù)據(jù)成員,不能被繼承,類外不能訪問(wèn),通過(guò)函數(shù)才能
this->id = id;
}
void print() {
cout << "string=" << name << " " << "id=" << id<< endl;
}
};
// 注意 C++中類的結(jié)尾是有;的,和java不同,我vs,ide編輯沒(méi)有在意。
//如果不寫關(guān)鍵字,默認(rèn)為private。
class B :virtual public A {
//B類public繼承A類,但是私有數(shù)據(jù)成員不能訪問(wèn)。
protected:
int id; //A類的id成員被覆蓋了。
public:
/*
父類構(gòu)造函數(shù)的初始化通過(guò)子類構(gòu)造函數(shù)初始化列表實(shí)現(xiàn),
*/
B(string na,int ida,int idb):A(na,ida){
cout << "B的構(gòu)造函數(shù)執(zhí)行"<<endl;
this->id = idb;
}
~B() {
cout << "B的析構(gòu)函數(shù)"<<endl;
}
void print() {
/*
基類同名的數(shù)據(jù)成員在派生類被覆蓋,成為不可見。
*/
cout << "A類被繼承的ID:" << A::id << endl;
cout <<"name:B"<< name<<" "<<"id:"<<id<<endl; //name是繼承A的。
}
};
class C:virtual public A{
//B類public繼承A類,但是私有數(shù)據(jù)成員不能訪問(wèn)。
protected:
int id;
public:
/*
父類構(gòu)造函數(shù)的初始化通過(guò)子類構(gòu)造函數(shù)初始化列表實(shí)現(xiàn),
*/
C(string na,int ida,int idc) :A(na,ida) {
cout << "C的構(gòu)造函數(shù)執(zhí)行" << endl;
this->id = idc;
}
~C() {
cout << "C的析構(gòu)函數(shù)" << endl;
}
void print() {
cout << "name:C" << name << " " << "id:" << id << endl;; //name是繼承A的。
}
};
//D類繼承B,C, 因?yàn)锽,C都繼承A,所以D類有2份A,這樣就會(huì)出現(xiàn)二義性問(wèn)題。
class D :public B,public C {
public:
void showId() {
/* cout << "id::" << id << endl;
如果這樣,就會(huì)產(chǎn)生二義性,D公有繼承了B,C protedted的id,
這里不知道訪問(wèn)哪一個(gè)。 但是可以通過(guò)域運(yùn)算符指定A,B,C繼承來(lái)的id。
*/
cout << "id::A" <<A::id << endl;
//通過(guò)域運(yùn)算符指定id。
}
/*
D繼承了,B,C。B,C繼承了A,即繼承了double da;
怎么訪問(wèn)它了。
cout<<da;
cout<<A::da; 都不行,無(wú)法指出是繼承B的,還是C的。
所以就要虛基類了。
*/
void showDa() {
cout << "B::da" << B::da << endl;
}
/*
在以前派生類只對(duì)其直接基類初始化,在由其直接子類對(duì)間接子類初始化
現(xiàn)在由于虛基類在派生類只有一份拷貝,所以這份數(shù)據(jù)必須由派生類給出。
因?yàn)轭怋,類C可能給出不同的構(gòu)造函數(shù),這樣對(duì)虛基類初始化會(huì)產(chǎn)生矛盾。
*/
D(string na, int ida, int idc) :C(na, ida, idc),
B(na, ida, idc), A(na, ida)
{
cout << "D的構(gòu)造函數(shù)執(zhí)行" << endl;
}
~D() {
cout << "D的析構(gòu)函數(shù)" << endl;
}
};
int main() {
A a("name_A", 111);
a.print();
cout << "-----------------------------" << endl;
//先執(zhí)行父類的構(gòu)造函數(shù),在執(zhí)行基類的構(gòu)造函數(shù)
B b("name_B",111, 222);
//這里是B的id,因?yàn)閜rivate屬性在子類不能訪問(wèn)。
b.print();
cout << "-----------------------------" << endl;
C c("name_C", 111, 333);
//這里是B的id,因?yàn)閜rivate屬性在子類不能訪問(wèn)。
c.print();
cout << "-----------------------------" << endl;
D d("name_D", 111, 444);
// id的二義性 可以通過(guò) ::域運(yùn)算符指定,解決。
d.showId();
// 準(zhǔn)備驗(yàn)證double da; 產(chǎn)生二義性的情況,這個(gè)就只能通過(guò)虛基類確定。
// setDa() 是會(huì)產(chǎn)生二義性的函數(shù),但是A是虛基類。
d.setDa(3.1415926);
d.showDa();
cout << "-----------------------------" << endl;
system("pause"); //vs要看析構(gòu)函數(shù)要去掉這一句。
return 0;
}
結(jié)果如下,可以對(duì)照代碼分析
結(jié)果圖.PNG
這里main函數(shù)的代碼如下:
int main() {
D d("name_D", 111, 444);
// id的二義性 可以通過(guò) ::域運(yùn)算符指定,解決。
d.showId();
// 準(zhǔn)備驗(yàn)證double da; 產(chǎn)生二義性的情況,這個(gè)就只能通過(guò)虛基類確定。
// setDa() 是會(huì)產(chǎn)生二義性的函數(shù),但是A是虛基類。
d.setDa(3.1415926);
d.showDa();
cout << "-----------------------------" << endl;
/* vs選擇開始執(zhí)行但不調(diào)試 */
// system("pause"); //vs要看析構(gòu)函數(shù)要去掉這一句。
return 0;
}
構(gòu)造函數(shù)和析構(gòu)函數(shù)執(zhí)行順序驗(yàn)證
只保留了D類.PNG
東西好多啊,c++ 講個(gè)語(yǔ)法就不少東西了
虛函數(shù),多態(tài)性,這個(gè)代碼挖了坑,后面在講,好累啊。