關於多重繼承的一些理解

2021-04-16 11:46:22 字數 4749 閱讀 1575

class base1

~base1(){}

void testfunc()

int abc;

};class base2

~base2(){}

void testfunc()

int abc;

};class son: public base1, public base2

~son(){}

void showabc()

};int main()

compiling...

main.cpp

f:/new study material/vc6test/main.cpp(76) : error c2385: 'son::testfunc' is ambiguous

f:/new study material/vc6test/main.cpp(76) : warning c4385: could be the 'testfunc' in base 'base1' of class 'son'

f:/new study material/vc6test/main.cpp(76) : warning c4385: or the 'testfunc' in base 'base2' of class 'son'

這說明編譯器搞不清楚你要使用哪乙個testfunc……

以下為**:

c++允許讓衍生類別同時直接繼承兩個以上的父類別,例如有a、b兩個類別,您可以使用下面的方式來讓c類別直接繼承這兩個類別:

class c : public a, public b    

// 實作

};上面也同時示範了在繼承之後的的構造函式呼叫,沒有引數的預設建構函式不用使用這種方式執行,它會自動被呼叫,而析構函式也是會自動執行。

多重繼承之後的建構函式執行順序,是依您撰寫程式時的順序由左而右決定,最後才是繼承後衍生類別,例如上面的例子中,會先執行a類別定義的建構函式,然後再執行b類別的建構函式,最後執行c類別的建構函式,而析構函式的執行則正好相反,先執行衍生類別的析構函式,然後再右向左執行,使用下面這個簡單的範例來示範:

#include 

using namespace std;

class fooa

~fooa()

}; class foob

~foob()

}; class fooc : public fooa, public foob

~fooc()

}; int main()

執行結果:

執行fooa建構函式

執行foob建構函式

執行fooc建構函式

執行fooc析構函式

執行foob析構函式

執行fooa析構函式

多重繼承時通常其中乙個基底類別作為private實作體,而其它的用以表現完全的抽象介面。

考慮您有乙個方法dorequest(),您事先並無法知道什麼型態的物件會被傳進來,或者是這個方法可以接受任何型別的物件,您想要操作物件上的某個特定方法,例如dosomething()方法,問題是傳進來的物件是任意的,除非您定義乙個抽象類別並宣告dosomething()抽象方法,然後讓所有的類別都繼承這個抽象類別,否則的話您的dorequest()方法似乎無法實作出來,實際上這麼作也沒有價值。

您可以藉由多重繼承來解決這個問題,例如先定義乙個抽象類別:

#ifndef irequest

#define irequest

class irequest ;

#endif

假設您的類別是以下的someobject類別的子類別:

#ifndef someobject

#define someobject

#include

using namespace std;

class someobject

private:

void otherfunction()

};#endif

為了滿足之前所提供的dorequest()的需求,您讓衍生類別同時繼承irequest與someobject類別,例如

#include "irequest.h"

#include "someobject.h"

#include

using namespace std;

class welcome : public someobject, public irequest

};

#include "irequest.h"

#include "someobject.h"

#include

using namespace std;

class hello : public someobject, public irequest

};

假設您設計了乙個dorequest()方法,雖然不知道hello與 welcome是什麼型態,但它們都繼承了irequest,所以dorequest()只要知道irequest定義了什麼公開介面,就可以操作hello與welcome的例項,而不用知道傳入的物件到底是什麼類別的例項,使用下面這個程式來測試:

#include 

#include "irequest.h"

#include "welcome.h"

#include "hello.h"

using namespace std;

void dorequest(irequest *request)

int main()

執行結果:

welcome!!

hello!!

在過去的學習中,我們始終接觸的單個類的繼承,但是在現實生活中,一些新事物往往會擁有兩個或者兩個以上事物的屬性,為了解決這個問題,c++引入了多重繼承的概念,c++允許為乙個派生類指定多個基類,這樣的繼承結構被稱做多重繼承

舉個例子,交通工具類可以派生出汽車和船連個子類,但擁有汽車和船共同特性水陸兩用汽車就必須繼承來自汽車類與船類的共同屬性。

由此我們不難想出如下的圖例與**:

當乙個派生類要使用多重繼承的時候,必須在派生類名和冒號之後列出所有基類的類名,並用逗好分隔。

//站點:www.***ev-lab.com   

#include  

using

namespace std; 

class vehicle 

void setweight(int weight) 

virtual

void showme() = 0; 

protected: 

int weight; 

}; 

class car:public vehicle//汽車 

void showme() 

;  class boat:public vehicle//船 

void showme() 

;  class amphibiancar:public car,public boat//水陸兩用汽車,多重繼承的體現 

void showme() 

上面的**從表面看,看不出有明顯的語發錯誤,但是它是不能夠通過編譯的。這有是為什麼呢?

這是由於多重繼承帶來的繼承的模糊性

帶來的問題。

先看如下的圖示:

在圖中深紅色標記出來的地方正是主要問題所在,水陸兩用汽車類繼承了來自car類與boat類的屬性與方法,car類與boat類同為amphibiancar類的基類,在記憶體分配上amphibiancar獲得了來自兩個類的setweight()成員函式,當我們呼叫a.setweight(3)的時候計算機不知道如何選擇分別屬於兩個基類的被重複擁有了的類成員函式setweight()。

由於這種模糊問題的存在同樣也導致了amphibiancar a(4,200,1.35f);執行失敗,系統會產生vehicle」不是基或成員的錯誤。

以上面的**為例,我們要想讓amphibiancar類既獲得乙個vehicle的拷貝,而且又同時共享用car類與boat類的資料成員與成員函式就必須通過c++所提供的虛擬繼承技術來實現。

我們在car類和boat類繼承vehicle類出,在前面加上virtual關鍵字就可以實現虛擬繼承,使用虛擬繼承後,當系統碰到多重繼承的時候就會自動先加入乙個vehicle的拷貝,當再次請求乙個vehicle的拷貝的時候就會被忽略,保證繼承類成員函式的唯一性。

修改後的**如下,注意觀察變化:

//站點:www.***ev-lab.com   

#include  

using

namespace std; 

class vehicle 

virtual

void showme() = 0; 

protected: 

int weight; 

}; 

class car:virtual

public vehicle//汽車,這裡是虛擬繼承 

;  class boat:virtual

public vehicle//船,這裡是虛擬繼承 

;  class amphibiancar:public car,public boat//水陸兩用汽車,多重繼承的體現 

注意觀察類建構函式的構造順序。

雖然說虛擬繼承與虛函式有一定相似的地方,但讀者務必要記住,他們之間是絕對沒有任何聯絡的!

關於熵的一些理解

對於理工科學生來說,熵 並不是乙個陌生的名詞。在諸如 大學物理 熱力學 和 資訊理論 等課程中都會有所介紹。但同時 熵 又是乙個顯得有點神秘的概念,看不見也摸不著。我最早是在高中物理課中聽說的,大概是在介紹 熱力學第二定律 時提到的。熱力學第二定律的內容是 熱力學過程是不可逆的 孤立系統自發地朝著熱...

關於float的一些理解

float是否脫離文件流,乙個父元素不設定overflow的話,子元素float,就不會把父元素撐開,換句話說,他就不會有高度,但是做個demo 父元素overflow hidden 子元素前兩個float,第三個不float,結果是第三個沒有clear浮動的元素,跟float的元素出現在同乙個位置...

關於android layout的一些理解

1 wrap content view的尺寸根據它的內容確定 match parent view的尺寸盡量和它的parent view group一樣大 2 獲得view的位置 position getleft gettop getright getleft getwidth getwidth 3 ...