最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

C++多繼承、多態(tài)、運行階段類型識別、四種類型轉(zhuǎn)換

2023-10-10 20:54 作者:虛云幻仙  | 我要投稿

#include <iostream>

using namespace std;


//C++允許多繼承,當子類繼承多個父類時需要解決父類之間成員名沖突

class ClassBaseA

{

????public:

???? ClassBaseA(int a = 0) :a(a) {}

???? int a;

???? void func() {}

};

class ClassBaseB

{

????public:

???? ClassBaseB(int a = 0) :a(a) {}

???? int a;

???? void func() {}

};

class ClassDeriveA:public ClassBaseA, public ClassBaseB //每個父類要分別寫訪問權(quán)限,父類之間逗號分隔

{

????public:

???? ClassDeriveA(int Aa = 0,int Ba=0)?

???? ???? :ClassBaseA(Aa), ClassBaseB(Ba) {} //每個父類都要初始化,如不使用默認無參構(gòu)造器就需要顯式指定

???? void invoke()?

???? {

???????? //func(); //二義性

???????? ClassBaseA::func(); //需要指明名稱空間

???????? ClassBaseB::func();

???????? ClassBaseB::a;

???????? ClassBaseA::a;

???? }

};


//當子類的多個基類繼承了同一個基類時,會產(chǎn)生多份同樣的成員,通過虛繼承解決

class ClassDerive1:virtual public ClassBaseA //關(guān)鍵字virtual

{

????//使用virtual派生子類的基類稱為虛基類(對virtual派生的子類而言)

????public:

???? ClassDerive1(int a = 0):ClassBaseA(a) {} //虛繼承不影響子類得到虛基類的成員

???? void func() {}

};

class ClassDerive2:virtual public ClassBaseA //ClassDerive1和2都虛繼承ClassBaseA,ClassBaseA稱為虛基類

{

????public:

???? ClassDerive2(int a = 0):ClassBaseA(a) {}

???? void func() {}

};

class ClassDeriveDerive :public ClassDerive1, public ClassDerive2 //子類繼承這些有共同父類的類,這里不需要virtual。子類正常繼承多個父類,多個父類虛繼承同一個類

{

????public:

???? void invoke() {

???????? a = 0; //虛基類的數(shù)據(jù)成員(即虛基類子對象)只有一份

???????? //func(); //如果中間類沒有shadow虛基類的函數(shù),則子類調(diào)用func()直接調(diào)用虛基類::func()且沒有二義性,如果某一個中間類shadow了虛基類的函數(shù),則根據(jù)虛繼承的規(guī)則,距離子類最近的func()生效,如果兩個中間類都shadow了該函數(shù),則兩個func()優(yōu)先級相同產(chǎn)生二義性

???? }

???? ClassDeriveDerive(int a = 0)

???????? :ClassDerive1(a), ClassDerive2(a), ClassBaseA(a) {} //與普通多繼承不同,除了指定直接基類的構(gòu)造器外還需要指定虛基類的構(gòu)造器,虛基類禁止通過中間類構(gòu)造器傳遞信息給基類,子類使用中間類構(gòu)造器初始化時只執(zhí)行中間類自身聲明的部分,該構(gòu)造器調(diào)用的基類構(gòu)造器部分不生效,如果不指定虛基類構(gòu)造器則調(diào)用默認構(gòu)造器無視中間類構(gòu)造器的虛基類部分,實際執(zhí)行順序與構(gòu)造器書寫順序無關(guān)

???? int b;

};

int maininherit9()

{

???? ClassDeriveDerive cdd;

???? ClassDerive1* cd1ptr = &cdd; //子類對象可賦給父類指針(賦值兼容),不會產(chǎn)生新的對象

???? ClassDerive2* cd2ptr = &cdd;

???? //cd1ptr->b; //父類指針無法調(diào)用子類獨有的內(nèi)容,且如果子類shadow了父類的成員,通過父類指針也只能訪問到父類的定義

???? return 0;

}


class ClassFactoryBase //可以使用工廠模式處理虛繼承產(chǎn)生的麻煩

{

????//使用默認的無參構(gòu)造器、析構(gòu)器,即在構(gòu)造階段不初始化任何東西

????protected:

???? int* arr;

???? int size;

????public:

???? void init(int size) //自定義初始化

???? {?

???????? this->size = size;?

???????? this->arr = new int[size];

???? }

???? void release() { delete[]arr; } //自定義釋放堆內(nèi)存

};

class ClassFactoryDerive1 :virtual public ClassFactoryBase

{

????protected:

???? int a;

????public:

???? void init(int size,int a) //shadow父類的初始化

???? {

???????? this->size = size;

???????? this->arr = new int[size];

???????? this->a = a;

???? }

};

class ClassFactoryDerive2 :virtual public ClassFactoryBase

{

????protected:

???? int b;

????public:

???? void init(int size,int b) //shadow父類的初始化

???? {

???????? ClassFactoryBase::init(size); //調(diào)用父類的初始化函數(shù)

???????? this->b = b;

???? }

};

class ClassFactoryDeriveDerive :public ClassFactoryDerive1, public ClassFactoryDerive2

{

????private:

???? int c;

????public:

???? void init(int size, int a,int b,int c) //每個子類都寫自己的初始化函數(shù)和釋放函數(shù)

???? {

???????? this->size = size;

???????? this->arr = new int[size];

???????? this->a = a;

???????? this->b = b;

???????? this->c = c;

???? }

???? void release() { delete[]arr; size = 0; a = 0; b = 0; c = 0; }

???? void func() {}

};

int mainfactory()

{

???? ClassFactoryDeriveDerive c; //創(chuàng)建對象,從祖父類構(gòu)造器開始逐一調(diào)用,但都沒有進行任何初始化操作

???? c.init(5, 1, 2, 3); //單獨初始化

???? c.func(); //正常調(diào)用

???? c.release(); //釋放

???? return 0;

}


class ClassBaseC

{

????private:

???? int basepri;

????public:

???? virtual int& getprimember() //virtual將函數(shù)變?yōu)樘摵瘮?shù),虛函數(shù)用于構(gòu)成多態(tài)

???? {

???? ????return basepri; //函數(shù)用來返回私有成員

???? }

};

class ClassDeriveC1 :public ClassBaseC

{

????private:

???? int derive1pri;

????public:

???? virtual int& getprimember() //重寫override虛函數(shù),要求函數(shù)簽名完全一致??墒÷詖irtual關(guān)鍵字

???? {

???? ????return derive1pri; //返回子類的私有成員

???? }

};

class ClassDeriveC2 :public ClassBaseC

{

????private:

???? int derive2pri;

????public:

???? virtual int& getprimember()

???? {

???? ????return derive2pri;

???? }

};

int mainpoly()

{

ClassBaseC base;

ClassDeriveC1 derive1;

ClassDeriveC2 derive2;

ClassBaseC* baseptr = &base; //父類指針指向父類對象

cout << &baseptr->getprimember() << endl;

cout << &base.getprimember() << endl; //調(diào)用函數(shù)得到父類的數(shù)據(jù)成員basepri,取址&運算符優(yōu)先級低于成員運算符.和間接成員運算符->,結(jié)果將成員的地址輸出

baseptr = &derive1; //父類指針指向子類對象

cout << &baseptr->getprimember() << endl; //通過父類指針調(diào)用到了子類重寫的虛函數(shù),得到了子類獨有的成員derive1pri,構(gòu)成了多態(tài)

cout << &derive1.getprimember() << endl;

baseptr = &derive2; //指向另外一個子類對象,結(jié)果同樣調(diào)用這個子類的成員函數(shù)

cout << &baseptr->getprimember() << endl;

cout << &derive2.getprimember() << endl;

//多態(tài)要求:1父類聲明虛函數(shù),2子類重寫虛函數(shù)(只有函數(shù)簽名完全一樣才構(gòu)成重寫,否則shadow父類的虛函數(shù))3通過父類指針指向子類對象,調(diào)用虛函數(shù)會調(diào)用到對象實際類型的函數(shù)成員

// 通常父類的虛函數(shù)公有,子類的虛函數(shù)訪問限制無所謂不會影響父類指針的函數(shù)調(diào)用,只要父類聲明為虛函數(shù),后代類的該函數(shù)均為虛函數(shù)

// 如果父類的虛函數(shù)返回父類引用或指針,子類重寫的虛函數(shù)允許修改為返回子類引用或指針,這稱為返回類型協(xié)變,協(xié)變只適用于這種情況,不能將void類型重寫為int,也不能將int類型重寫為long

//baseptr = new ClassDeriveC1; //如果用父類指針指向堆內(nèi)存

//delete baseptr; //釋放對象時會調(diào)用父類的析構(gòu)器,導(dǎo)致不完全析構(gòu),正常delete子類指針時會先調(diào)用子類析構(gòu)器再調(diào)用父類析構(gòu)器,delete父類指針跳過了子類的析構(gòu)

return 0;

}


class AbstractBaseClass //抽象基類

{

????public:

???? virtual void connect(const char* address) = 0; //在virtual虛函數(shù)聲明的末尾添加 = 0 使函數(shù)變?yōu)榧兲摵瘮?shù),聲明純虛函數(shù)可以不寫函數(shù)定義,擁有純虛函數(shù)的類不能實例化,類成為抽象基類,只能用于繼承,用于多態(tài),(注意抽象基類和虛基類不同)

???? virtual ~AbstractBaseClass() {} //使用堆內(nèi)存構(gòu)成多態(tài)時,需要將父類的析構(gòu)器virtual,即析構(gòu)器也要多態(tài)。通常抽象基類和使用虛函數(shù)的基類的析構(gòu)器都要虛,即多態(tài)的父類必須虛析構(gòu),父類的析構(gòu)虛了之后,后代的所有析構(gòu)器也都為虛函數(shù),通過父類引用、指針調(diào)用析構(gòu)器時會調(diào)用實際子類的析構(gòu)器,且析構(gòu)器中在用戶定義的代碼(如果有)之后會逐級調(diào)用父類的析構(gòu)器。

};

class ClassDeriveD1 :public AbstractBaseClass

{

????public:

???? virtual void connect(const char* address) //子類需實現(xiàn)父類的所有純虛函數(shù)才能夠?qū)嵗?。否則依然為抽象類

???? {

???? ????cout << "TCP connect" << endl << address << endl;

???? }

};

class ClassDeriveD2 :public AbstractBaseClass

{

????public:

???? virtual void connect(const char* address) //virtual可省略

???? {

???? ????func(address); //可以調(diào)用子類獨有的函數(shù)實現(xiàn)父類的純虛函數(shù)。每個子類都有不同的實現(xiàn)方式,對外統(tǒng)一使用父類屏蔽差異

???? }

???? void func(const char* address) {

???? ????cout << "UDP connect" << endl << address << endl;

???? }

};

class ClassDeriveD3 :public ClassDeriveD2 //抽象類/接口的實現(xiàn)類的子類,會繼承實現(xiàn)類的虛函數(shù)定義,可以按需再次重寫

{

????public:

???? ~ClassDeriveD3() { cout << "ddd" << endl; }

};

int mainabstract()

{

???? AbstractBaseClass* ptr = new ClassDeriveD1;

???? ptr->connect("127.0.0.1");

???? delete ptr;

???? ptr = new ClassDeriveD2;

???? ptr->connect("127.0.0.1");

???? delete ptr;

???? ptr = new ClassDeriveD3;

???? ptr->connect("127.0.0.1");

???? delete ptr; //抽象基類virtual析構(gòu)器后,即便實現(xiàn)類沒有virtual,依然調(diào)用到了實現(xiàn)類的子類的析構(gòu)器

???? //在父類的普通成員函數(shù)中通過this指針調(diào)用虛函數(shù)和在外側(cè)通過父類指針調(diào)用虛函數(shù)一樣,都可以構(gòu)成多態(tài)。

???? //但在父類的構(gòu)造器和析構(gòu)器中使用this指針無法構(gòu)成多態(tài),因為父類的構(gòu)造器先于子類的構(gòu)造器執(zhí)行,此時還沒有初始化子類所以無法調(diào)用,而子類的析構(gòu)器先于父類的析構(gòu)器,在父類析構(gòu)器執(zhí)行時子類獨有的空間已經(jīng)釋放,無法調(diào)用

???? return 0;

}


class ClassVirtual1 //聲明一個帶有虛函數(shù)的類

{

????public:

???? int c;

???? virtual void func() { cout << "base func" << endl; };

};

int mainvtable1()

{

???? cout << sizeof(ClassVirtual1) << endl; //結(jié)果為16,只要類中含有虛函數(shù),在創(chuàng)建對象時會在內(nèi)存塊最前面存放一個指向虛函數(shù)表的指針,本系統(tǒng)指針為8字節(jié),只要有虛函數(shù)表的指針,內(nèi)存空間會變?yōu)?字節(jié)對齊,所以雖然實際使用了12字節(jié),卻占用了16字節(jié)

???? ClassVirtual1 c;

???? __int64 v = *(__int64*)&c; //&c是對象的地址,從該地址開始的前8字節(jié)是指向虛函數(shù)表的指針,指針的值/地址也是數(shù)值類型,將地址解釋成8字節(jié)__int64/longlong類型的值的地址,解引用后得到指針的值/64位int的值,這個值是虛函數(shù)表的地址

???? //虛函數(shù)表中存放有對象的類及祖先中所有虛函數(shù),表中每個元素都是一個函數(shù)指針,即元素是*func,表是*func[]

???? void(**pvtable)() = (void(**)())v; //所以將v的類型轉(zhuǎn)換為指向函數(shù)指針的指針,這個指針變量的值/v的值是指針數(shù)組首元素的地址即&(pfunc),所以用指向函數(shù)指針的指針來接收函數(shù)指針數(shù)組首元素的地址/函數(shù)指針的地址

???? cout << *pvtable << endl; //*pvtable得到首個函數(shù)指針的值,按指針數(shù)組的用法表示為pvtable[0],只有含有虛函數(shù)的類才有虛函數(shù)表,所以首元素函數(shù)指針一定存在

???? (*(*pvtable))(); //通過指針調(diào)用函數(shù),結(jié)果為調(diào)用c.func()

???? return 0;

}

class ClassVirtual2 :public ClassVirtual1

{

????public:

???? void func() { cout << "derive func" << endl; }

???? void func(int a) { cout << "derive func" << endl; }

???? void func2() { cout << "derive func2" << endl; }

};

int mainvtable2()

{

???? ClassVirtual2 c;

???? (*(**(void(***)()) & c))(); //前8字節(jié)是存儲*func[]的指針,這個指針的值是**func類型的值,這個指針是***func類型,或者說這個地址上存儲了虛函數(shù)表的地址作為值,這個值是*func[]類型,這個地址是&(*func[])所以再加一個*,對指向虛函數(shù)表的指針解引用一次得到虛函數(shù)表,解引用兩次得到首元素即函數(shù)指針,對函數(shù)指針解引用加括號調(diào)用

???? //結(jié)果為"derive func"?

???? cout << *(void(***)()) & c << endl; //無論創(chuàng)建多少個CV2對象,虛函數(shù)表指針都指向一張表

???? ClassVirtual1 cc;

???? cout << *(void(***)()) & cc << endl; //父類的虛函數(shù)表地址不同于子類

???? //作為CV1的子類,CV2對父類虛函數(shù)表的副本進行修改和擴充,如果函數(shù)簽名完全相同的虛函數(shù)會覆蓋掉父類的指針,如果是父類沒有的虛函數(shù)會往后擴充。

???? //所以多態(tài)的原理是,將對象的虛函數(shù)表的指針存儲在對象的內(nèi)存空間的首位,無論以哪個父類指針指向該對象,都不影響讀取首位的虛函數(shù)表,而虛函數(shù)表中子類重寫的函數(shù)的地址直接覆蓋了父類的指針的值,所以通過虛函數(shù)表無論如何也調(diào)用不到父類被重寫的原函數(shù),而函數(shù)名相同、函數(shù)簽名不同的經(jīng)過傾軋實際為不同的函數(shù)所以沒有被virtual不會添加到虛函數(shù)表中,這雖然不會重寫原函數(shù),但會shadow,通過子類對象無法正常訪問到,但可以通過虛函數(shù)表訪問,而如果將函數(shù)名相同、函數(shù)簽名不同的函數(shù)也virtual,不會重寫原函數(shù)會往后擴充,但同樣會shadow使得子類無法正常訪問父類的原函數(shù),但可以通過虛函數(shù)表訪問

???? return 0;

}


#include <typeinfo> //提供與typeid有關(guān)的函數(shù)及運算符重載

int mainRTTI()

{

???? //run time type identification運行階段類型識別RTTI

???? ClassVirtual2 c;

???? ClassVirtual1* ptr = &c;

???? cout << typeid(ptr).name() << endl; //typeid關(guān)鍵字,返回包含運算對象信息的type_info對象的引用,.name()返回名字,c++沒有規(guī)定name返回的格式,typeid(ptr)返回指針變量的信息

???? cout << typeid(*ptr).name() << endl; //解引用后,typeid(*ptr)返回對象的實際類型信息,typeid通常用于多態(tài)中顯示對象實際信息

???? if (typeid(*ptr) == typeid(ClassVirtual2)) //判斷*ptr對象的類型是否為ClassVirtual2類(子類不算),typeinfo頭文件重載了賦值運算符== !=

???? {

???? ????cout << "*ptr is an instance of ClassVirtual2" << endl;

???? }

???? ClassVirtual2* realptr = static_cast<ClassVirtual2*>(ptr); //子類地址賦值給父類指針不需要顯式轉(zhuǎn)換,父類指針/地址轉(zhuǎn)換為子類指針時需要顯式轉(zhuǎn)換。如果使用static_cast<類型>(要轉(zhuǎn)換的變量),不會判斷該對象的實際類型是否為要轉(zhuǎn)換的類型或子類,即使用static_cast可以將指向父類對象的父類指針轉(zhuǎn)換為子類指針而不報錯,不安全,這個轉(zhuǎn)換是編譯階段執(zhí)行的,編譯器不會查看上下文判斷該對象的實際類型。但如果將指針轉(zhuǎn)換為沒有繼承關(guān)系的其他指針會報錯

???? //報錯:AbstractBaseClass* ptr2 = static_cast<AbstractBaseClass*>(ptr); 編譯器判斷兩種類型無繼承關(guān)系

???? //static_cast轉(zhuǎn)換需要源類型可以隱式轉(zhuǎn)換為目標類型或者目標類型可以隱式轉(zhuǎn)換為源類型,即使派生類沒有定義使用基類的轉(zhuǎn)換構(gòu)造器但因為派生類可以隱式轉(zhuǎn)換為基類所以static_cast<派生類*>基類* 能通過編譯。static_cast不止用于類,任何可以隱式轉(zhuǎn)換的兩種類型都可以使用該轉(zhuǎn)換運算符

???? ClassVirtual2* realptr2 = dynamic_cast<ClassVirtual2*>(ptr); //dynamic_cast轉(zhuǎn)換運算符只用于多態(tài)的指針/引用轉(zhuǎn)換。動態(tài)轉(zhuǎn)換,對于轉(zhuǎn)換指針在運行時判斷指針指向?qū)ο蟮膶嶋H類型,如果對象是目標類型的實例或后代類型的實例則成功轉(zhuǎn)換,除此以外均返回null,對于轉(zhuǎn)換引用如果轉(zhuǎn)換不成功會引發(fā)bad_cast異常

???? if (realptr2 != NULL) //判斷是否轉(zhuǎn)換成功,安全,可以和上一句合并為if( ClassVirtual2* realptr2 = dynamic_cast<ClassVirtual2*>(ptr) ){}

???? {

???? ????cout << "*ptr is an instance of ClassVirtual2" << endl;

???? }

???? //dynamic_cast會檢測基類指針是否能安全轉(zhuǎn)換為派生類指針而static_cast只檢測兩種類型是否相關(guān)

???? AbstractBaseClass* ptr2 = reinterpret_cast<AbstractBaseClass*>(ptr); //reinterpret_cast將變量重新解釋為目標類型,完全不檢驗類型。完全不安全。不能刪除const特性,不能將源類型轉(zhuǎn)換為size更小的類型,不能將函數(shù)指針和數(shù)據(jù)指針相互轉(zhuǎn)換。

???? //typeid和dynamic_cast通常只用于多態(tài),假設(shè)有A繼承B繼承C,A的對象賦給C的指針,如果將C指針轉(zhuǎn)換為B指針,無法通過typeid(*指針)==typeid(B)得到是否能轉(zhuǎn)換成功,使用dynamic_cast<B*>(C指針)判斷是否NULL即可完成中間類的轉(zhuǎn)換及確認

???? //通常,抽象類型/接口夾在高層業(yè)務(wù)邏輯和底層實現(xiàn)之間(高層和底層都依賴抽象類型),高層業(yè)務(wù)邏輯使用抽象類通過多態(tài)完成業(yè)務(wù)邏輯,即使用抽象的稱為高層。實現(xiàn)抽象的稱為底層實現(xiàn)。通常高層業(yè)務(wù)邏輯一經(jīng)敲定很難更改/基本不變,需要擴展、修改業(yè)務(wù)時通過調(diào)整、追加底層實現(xiàn)來完成。

???? return 0;

}


class Port

{

???? char* brand;

???? char style[20];

???? int bottles;

????public:

???? Port(const char* br = "none", const char* st = "none", int b = 0) :bottles(b)?

???? {

???????? brand = new char[strlen(br) + 1];

???????? strcpy(brand, br);

???????? strncpy(style, st, 19);

???????? style[19] = 0;

???? }

???? Port(const Port& p) :bottles(p.bottles)

???? {

???????? brand = new char[strlen(p.brand) + 1];

???????? strcpy(brand, p.brand);

???????? strcpy(style, p.style);

???? }

???? virtual ~Port() { delete[]brand; } //釋放動態(tài)內(nèi)存

???? Port& operator=(const Port& p)

???? {

???????? if (&p == this) //賦值運算符重載必須先排除調(diào)用對象給自己賦值的特例

???????? ????return *this;

???????? delete[]brand;

???????? brand = new char[strlen(p.brand) + 1];

???????? strcpy(brand, p.brand);

???????? strcpy(style, p.style);

???????? bottles = p.bottles;

???? }

???? Port&operator+=(int b)

???? {

???????? bottles += b;

???????? return *this;

???? }

???? Port&operator-=(int b)

???? {

???????? bottles -= b;

???????? return *this;

???? }

???? int BottleCount()const { return bottles; }

???? virtual void show()const

???? {

???? ????cout << "Brand:" << brand << "\nKind:" << style << "\nBottles:" << bottles << endl;

???? }

???? friend ostream& operator<<(ostream& os, const Port& p)

???? {

???????? os << p.brand << "," << p.style << ',' << p.bottles;

???????? return os;

???? }

};

class VintagePort :public Port

{

???? char* nickname;

???? int year;

????public:

???? VintagePort() :year(0) //隱式調(diào)用Port()構(gòu)造器,執(zhí)行基類的動態(tài)分配

???? {

???????? nickname = new char[1]; //派生類的動態(tài)分配

???????? nickname[0] = 0;

???? }

???? VintagePort(const char* br, const char* st, int b, const char* nn, int y) :Port(br, st, b), year(y)

???? {

???????? nickname = new char[strlen(nn) + 1];

???????? strcpy(nickname, nn);

???? }

???? VintagePort(const VintagePort& vp) :Port(vp), year(vp.year) //使用Port(const Port&)拷貝構(gòu)造器傳參VintagePort對象,基類引用可以指向派生類對象,對當前對象的Port部分進行初始化

???? {

???????? nickname = new char[strlen(vp.nickname) + 1];

???????? strcpy(nickname, vp.nickname);

???? }

???? ~VintagePort() { delete[]nickname; } //基類虛析構(gòu),派生類需要手動釋放派生類中聲明、分配的動態(tài)內(nèi)存,用戶定義代碼之后會自動調(diào)用基類的析構(gòu)器釋放基類的動態(tài)內(nèi)存

???? VintagePort& operator=(const VintagePort& vp) //因為派生類中也使用了動態(tài)內(nèi)存,所以需要自定義賦值運算符重載

???? {

???????? if (&vp == this)

???????? ????return *this;

???????? Port::operator=(vp); //顯式調(diào)用基類的賦值運算符,對調(diào)用對象的Port部分進行賦值(派生類的隱式的賦值運算符重載也會調(diào)用基類的賦值運算符來設(shè)置基類部分成員)

???????? delete[]nickname;

???????? nickname = new char[strlen(vp.nickname) + 1];

???????? strcpy(nickname, vp.nickname);

???????? year = vp.year;

???????? return *this;

???? }

???? void show()const

???? {

???????? Port::show(); //調(diào)用基類的show

???????? cout << "Nickname:" << nickname << "\nyear:" << year << endl;

???? }

???? friend ostream& operator<<(ostream& os, const VintagePort& vp)

???? {

???????? os << (const Port&)vp << ',' << vp.nickname << ',' << vp.year; //友元函數(shù)不屬于類不能通過作用域解析運算符調(diào)用,通過將派生類引用類型轉(zhuǎn)換為基類引用類型來匹配使用基類引用類型的插入運算符

???????? return os;

???? }

};


class Person

{

???? string first_;

???? string last_;

????public:

???? Person(const char* first = "F", const char* last = "L") :first_(first), last_(last) {}

???? virtual ~Person() {}

???? virtual void Show()

???? {

???? ????cout << first_ << ' ' << last_ << endl;

???? }

};

class Gunslinger:virtual public Person

{

???? double draw_;

???? int ke_;

????public:

???? Gunslinger(const char* first = "G", const char* last = "L", double draw = 1.0, int ke = 2) :Person(first, last), draw_(draw), ke_(ke) {}

???? void gShow()

???? {

???? ????cout << "time:" << draw_ << " ke:" << ke_ << endl;

???? }

???? virtual void Show()

???? {

???????? Person::Show();

???????? gShow(); //模塊化,將派生類的新內(nèi)容單獨寫一個函數(shù)在這里調(diào)用,以這個類為基類派生的類可以通過gShow()只顯示這個類獨有的內(nèi)容避免兩次調(diào)用Person::Show()

???? }

???? double Draw() { return draw_; }

};

class PokerPlayer :virtual public Person

{

????public:

???? PokerPlayer(const char* first = "P", const char* last = "P") :Person(first, last) {}

???? int Draw()

???? {

???? ????return rand() % 52 + 1;

???? }

};

class BadDude :public Gunslinger, public PokerPlayer

{

???? void Draw() {} //私有禁用,避免二義性

????public:

???? BadDude(const char* first = "B", const char* last = "D", double draw = 1.0, int ke = 2) :Person(first, last), Gunslinger(first, last, draw, ke), PokerPlayer(first, last) {}

???? double Gdraw() { return Gunslinger::Draw(); }

???? int Cdraw() { return PokerPlayer::Draw(); }

???? void Show()

???? {

???? PokerPlayer::Show(); //PokerPlayer沒有重新定義show,否則應(yīng)調(diào)用Person::show、PokerPlayer::pShow和Gunslinger::gShow來避免重復(fù)展示姓名

???? Gunslinger::gShow();

???? }

};


C++多繼承、多態(tài)、運行階段類型識別、四種類型轉(zhuǎn)換的評論 (共 條)

分享到微博請遵守國家法律
九台市| 远安县| 万山特区| 文昌市| 芦溪县| 高邮市| 营山县| 酒泉市| 太仓市| 常熟市| 平湖市| 常州市| 高台县| 雷州市| 年辖:市辖区| 长沙市| 溆浦县| 驻马店市| 丰都县| 金堂县| 闸北区| 张家界市| 百色市| 博白县| 龙川县| 双流县| 茌平县| 科技| 怀来县| 新巴尔虎左旗| 犍为县| 福安市| 大理市| 丰台区| 铅山县| 蚌埠市| 武强县| 双牌县| 孟村| 巴东县| 和龙市|