2013-07-21 56 views
1

這是一個Python和C++問題。python vs C++中的多重繼承

我正在試驗多重性,我遇到了這個例子。

B1 B2 
\/
    D 

說我有兩個(獨立?)父類B1, B2和一個子類D。我們只對class D的對象感興趣。

class B1: 
    def f1(self): 
     print "In f1" 

class B2: 
    def f2(self): 
     self.f1() 

class D (B1, B2): 
    def fD(self): 
     self.f2() 

d = D() 
d.fD() 

Output: In f1 

有趣的(至少對我來說)是class B2並不知道有關class B1,但f2可以調用self.f1(),沒有任何問題。

我試圖複製在C++這個確切的事情,我不能讓它工作,因爲我不知道如何從f2調用f1做。

class B1 { 
    public: 
    virtual ~B1() {} 
    virtual void f1() { cout << "In f1" << endl; } 
}; 

class B2 { 
    public: 
    virtual ~B2() {} 
    virtual void f2() { /* What goes here?? */ } 
}; 

class D : public B1, public B2 { 
    public: 
    void fD() { f2(); } 
}; 

所以,我想知道如何/爲什麼Python可以處理這個,但C++不能?

此外,我們可以對C++代碼做些什麼最小的修改,使其像Python代碼一樣?

+3

這在Python中並不是很有趣。它只是試圖通過一個MRO(方法解析順序)樹(動態地)解析給定的屬性(它比由於所有不同的規則尋找屬性更復雜一點,但它是關於如何總結它的)。樹MR(方法解析)*始終*從接收方開始,接收方是使用self的當前對象實例 - 這也是Python允許覆蓋和多態的方式 - 而不是方法的定義類型。要調用特定類型的方法,請參閱'TheType.method(self,..)' – user2246674

+0

@ user2246674:當類不是「新風格」(即從'object'派生)時,這是否爲真?如果這很重要,那麼應該編輯答案。 –

回答

1

我們可以對C++代碼做些什麼微小的修改,使其像Python代碼一樣?

簡短回答:你不能。 B2不知道它將構成一個子類的一部分,它也有B1作爲超級類。

龍答:你可以,如果你使用一些難看的向下轉換(基本上是鑄造thisD*)。但它可能不是一個好主意,因爲*this不一定是D

0

我想知道/爲什麼Python可以處理這個問題,但C++不能?

這是因爲Python是動態類型的,C++是靜態類型的。

我們可以對C++代碼做些什麼微小的修改,使它的行爲像Python代碼一樣?

如果你想在Python中編程,你知道在哪裏可以找到它。用C++編程使用Python的方式是反地道的,並且通常被忽視。也就是說,如果你想要這樣做,你可以使用dynamic_cast<B2*>(this)

1

這適用於python,因爲B2類中的名稱f1正在運行時解析。這是「鴨子打字」 - self中的對象引用只需要有一個有效的f1即可進行調用,當您以這種方式構造它時,它會執行此操作。

在C++中獲得類似行爲的最類似C++的方式是Curiously recurring template pattern。您的C++版本B2需要知道它是什麼的一部分。使其成爲其派生類型的模板可以爲您提供一種「乾淨」的方式來執行其他人建議的dynamic_cast。它更乾淨,因爲每個從它派生的類都會有一個新類B2<T>。每個專業化將有一個獨特的f2,它使用正確的投射來到右邊f1。它的工作原理與python版本非常相似,只需要一個可調用的f1(儘管在編譯時而不是運行時)。

class B1 { 
    public: 
    virtual ~B1() {} 
    virtual void f1() { cout << "In f1" << endl; } 
}; 

template <typename Derived> 
class B2 { 
    public: 
    virtual ~B2() {} 
    virtual void f2() { dynamic_cast<Derived *>(this)->f1(); } 
}; 

class D : public B1, public B2<D> { 
    public: 
    void fD() { f2(); } 
};