2017-08-10 37 views
1

說我得到了下面的(僞)代碼:鑽石傳承 - 調用所有父功能

class base{ 
public: 
    virtual void callMe() = 0; 
    virtual void doRender() = 0; 
} 

class a : public base{ 
public: 
    virtual void callMe(){/*doA*/} override; 
} 

class b : public base{ 
public: 
    virtual void callMe(){/*doB*/} override; 
} 

class myClass : public base, public a, public b{ 
public: 
    virtual void doRender(){ 
     this->a::callMe(); 
     this->b::callMe(); 
    } override; 
} 

會不會有以不同的方式寫的方法嗎?喜歡的東西:

class myClass : public base, public a, public b{ 
public: 
    virtual void doRender(){ 
     this->allSupers::callMe(); 
    } override; 
} 

我與這個目標是有一個基類,可以擴展到具有不同的「功能」,所有這些都必須在doRender執行。

我知道,我當然可以通過在基礎函數指針列表,在這種構造在子類中把自己的職能的手段跟蹤這些功能,但我想避免這種情況。不得不遍歷這些函數在我的最終doRender中仍然給我至少三行代碼。 (或一個長不可讀線。)

我打開使用模板建議。

+1

要調用函數的基類使用'''a ::: doRender()'''。從具有相同基類的多個類繼承似乎很危險,是否有實際的用例? – Freakyy

+1

@Freakyy是的,有一個實際的用例。我有4個「對象」,這些對象在渲染時都需要執行不同的功能,而大多數功能確實存在於兩個或三個對象中。我知道如何調用基本函數,在我的例子中,我習慣使用this->來區分本地函數和靜態函數。如果你知道你在做什麼,那麼在C++中多類繼承並不危險。關於鑽石問題有很多很好的解讀,正是這一點。 –

+0

「我當然可以通過基本函數指針列表來跟蹤這些函數」:在這種情況下,您絕對缺少虛擬繼承。當你的代碼代表,你沒有一個基地'base',而是三個:一個是直接的基地'myClass',另兩個基地'了'和'B'都有自己的'基地實例作爲他們的基地。所有三個都是彼此不同的。如果你只想要一個,就像引用暗示的那樣,只要你聲明'base'爲基類,就必須使用'virtual'關鍵字。 – cmaster

回答

1

根據手頭你實際的問題,您可能能夠使用mixin的風格。從本質上講,你可以在每個班級致電自己callMe結束(或begining)下一callMe。一個好處是callMe不需要是虛擬功能。下面是一個小例子(online):

#include <iostream> 

class base 
{ 
public: 
    void callMe() {}; // Empty base case 
    virtual void doRender() = 0; 
}; 

template <class super> 
class a : public super 
{ 
public: 
    void callMe() 
    { 
     std::cout << "doA" << '\n'; 

     super::callMe(); // Call the next 
    }; 
}; 

template <class super> 
class b : public super 
{ 
public: 
    void callMe() 
    { 
     std::cout << "doB" << '\n'; 

     super::callMe(); // Call the next 
    }; 
}; 

template <class super> 
class myClass_t : public super 
{ 
public: 
    void doRender() 
    { 
     super::callMe(); 
    }; 
}; 

using myClass = myClass_t<a<b<base> > >; // Defining the order of evaluation; 

int main() 
{ 
    myClass m; 
    m.doRender(); 
} 
+0

不是一個壞主意。我不知道是否有辦法做到這一點,而不必在callMe的底部打電話,但有一個upvote;) –

0

隨着可變參數模板,你可以這樣做:

template <typename ... Ts> 
class myClassTs : public base, public Ts... 
{ 
public: 
    virtual void doRender(){ 
     int dummy[] = {0, (Ts::callMe(), void(), 0)...}; 
     static_cast<void>(dummy); // Silent warning for unused variable 
    } override; 
} 

using myClass = myClassTs<a, b>; 

而且在C++ 17,這將是

template <typename ... Ts> 
class myClassTs : public base, public Ts... 
{ 
public: 
    virtual void doRender(){ 
     (static_cast<void>(Ts::callMe()), ...); 
    } override; 
} 
+0

好。如何爲這個結構定義評估順序? – Jonas

+0

@Jonas:它被指定;-),它是從左至右,因此對於'類myClassTs ',這將是'T1 ::的CallMe(); T2 ::的CallMe();'。 – Jarod42

+0

我是否有權聲明,如果它在基類中,它甚至可以工作?你能解釋'0,'和'void(),0)'是什麼意思嗎?我假設'0,'是讓它在沒有任何模板參數的情況下工作,但是我對'void(),0)'完全喪失了。 –