2017-08-10 7 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)'完全丧失了。 –