定义多次继承的虚方法

时间:2018-04-30 09:23:51

标签: c++

我一直试图找到这个问题的答案,但我不能(我甚至不知道如何正确地制定这个问题)所以我决定在StackOverflow上写我的第一篇文章=)。

上下文如下:

我有这个父类:

class Parent
{
public:
    Parent(){};
    void foo(void)
    {
        //Do some common things
        bar();
        //Do some more common things
    };
protected:
    virtual void bar(void) = 0;
};

我想创建一个无限量的派生Childs:

class Child1 : public Parent
{
public:
    Child1() : Parent(), child1Variable(0) {};
protected:
    virtual void bar(void) = 0;
private:
    uint32_t child1Variable;
};

class Child2 : public Parent
{
public:
    Child2() : Parent(), child2Variable(0) {};
protected:
    virtual void bar(void) = 0;
private:
    uint32_t child2Variable;
};

.
.
.

class ChildN : public Parent
{
public:
    ChildN() : Parent(), childNVariable(0) {};
protected:
    virtual void bar(void) = 0;
private:
    uint32_t childNVariable;
};

原因主要是不重复父foo()

中的代码

然后我想创建我的最终可实例化类,例如:

class ExampleFinal : public Child1, public Child3, public Child27
{
    //How to define Child1::bar(), Child3::bar() and Child27::bar() ??
private:
    void bar(void); //????
};

所以问题是:

  1. 如何定义(滥用符号)ExampleFinal::Child1::barExampleFinal::Child3::bar,...
  2. 的方法
  3. 我是否如此坚持这一点,以至于我忽视了一个更简单的解决方案?
  4. 最终目标是能够做到这样的事情:

    ExampleFinal test;
    test.Child1::foo(); //should end up on "ExampleFinal::Child1::bar"
    test.Child3::foo(); //should end up on "ExampleFinal::Child3::bar"
    

    谢谢!

1 个答案:

答案 0 :(得分:2)

实现ExampleFinal::bar()(旁注:bar(void)是一个在C ++中没用的C-ism)会覆盖你一次声明的所有bar。如果您想拥有不同的版本,则需要插入另一层类:

struct GrandChild1 : Child1 {
    void bar() override { /*...*/ }
};

// And so on...

struct ExampleFinal : GrandChild1, GrandChild3, GrandChild27 {
    // Nothing needed here.
};

然后您描述的行为将起作用。但请注意,您的继承图表示ExampleFinal每个Parent 有一个Child子对象。这本身不是问题,但可能无法模拟你想要的东西 - 也许你需要虚拟继承,但要注意兔子洞。

如果要保留ChildN::bar内所有ExampleFinal的覆盖,您可以添加标记分派来识别它们,但需要再花一次虚拟呼叫:

struct Parent {
    void foo() {
        bar();
    };

protected:
    template <class Child>
    struct tag { };
    virtual void bar() = 0;
};

struct Child1 : Parent {
protected:
    virtual void bar(tag<Child1>) = 0;

    void bar() final override {
        return bar(tag<Child1>{});
    }

    int child1Var;
};

struct Child2 : Parent {
protected:
    virtual void bar(tag<Child2>) = 0;

    void bar() final override {
        return bar(tag<Child2>{});
    }

    int child2Var;
};

struct ExampleFinal : Child1, Child2 {
protected:
    using Parent::tag;

    void bar(tag<Child1>) final override {
        std::cout << "Child1::bar\n";
    }

    void bar(tag<Child2>) final override {
        std::cout << "Child2::bar\n";
    }
};

请注意,bar()bar(tag<ChildN>)网桥很容易隐藏在宏后面。如果您想避免第二次虚拟呼叫的费用,也可以在此处应用CRTP。