多继承和数据成员

时间:2011-06-25 08:14:36

标签: c++ oop multiple-inheritance

我从未使用多重继承,偶然发现了一个我从未遇到的设计问题。

class A {
     //..methods..
}

class B : public A {
    int b;
    //...methods..
}

class C : public A {
    int c1,c2;
}

class D : public B,public C {
}

这是经典钻石。事实是C实际上只是一个A,有两个额外的整数。而D实际上只是BC的聚合,但我觉得多重继承不是为了制作这样的东西。或者可能还有其他最佳做法。

我试图实现多重继承的原因是我想写一个像void func(A*)这样的函数,并将它传递给AD类指针。我的天真尝试是做一个简单的演员:

void func(A* a) { // <-- I call this with a A or D pointer
   // ..do something with A members..

    if(is_the_case) { // <-- Im sure the passed "a" pointer is actually a *D
        D* d = (D*)a;
       // ..do something with the extra 2 ints provided by the C class..
    } 
}

不起作用..编译得很好,但是在执行if(is_the_case)时我有一个非常奇怪的行为,清除了2个额外的整数c1c2,也清除{{1 }(由b继承)。

我对钻石问题进行了重新考虑,但是层次结构中只有一个B(和2 B),所以我不明白为什么A被清除了。只是为了尝试,我在bB声明中使用了公共虚拟。现在每个演员都是编译错误,除非我使用C ..

有人能说清楚幕后发生了什么吗?考虑到其他类如:

,最佳做法是什么
dynamic_cast

也就是说,其他类只是派生自class E : public A { int e; //..methods.. } class F : public E,public C { } 的类的聚合+由A继承的两个额外的int,并且可以传递给需要C <的函数/ p>

谢谢,尽我所能尽可能清楚......

3 个答案:

答案 0 :(得分:4)

你的代码是有效的,因为你使用的是C风格的强制转换,它可以是reinterpret_cast,我的理解是你可以reinterpret_cast在任意两种指针类型之间,即使它没有合理。从多重继承的基础转换为更多派生类时,必须使用dynamic_caststatic_cast会产生编译时错误。事实上,dynamic_cast同时完成了这两项工作。

void func(A* a) { // <-- I call this with a A or D pointer
   // ..do something with A members..

    if(D* d = dynamic_cast<D*>(a)) { // a definitely points to a D
        // and we got a guaranteed good pointer too
    } 
}

这是为什么应该避免使用C风格的演员表的一个很好的例子。

答案 1 :(得分:1)

您可以阅读多重继承here

您需要做的是实际上继承下一个类:

class B : virtual public A {
    int b;
    //...methods..
};

class C : virtual public A {
    int c1,c2;
};

答案 2 :(得分:1)

我不知道为什么你会看到这种行为。如注释中所述,您描述的代码不应该编译。

是否存在设计问题?是。不要基于查询对象的类型明确地做出选择。这就是虚拟功能的用途。

class A
{
public:
    virtual void prepare_for_list_insertion() {}
};

class B : public A
{
    int b;
};

class C : public A
{
private:
    int c1, c2;

protected:
    void clear() { c1 = c2 = 0; }
};

class D : public B, public C
{
public:
    void prepare_for_list_insertion()
    {
        clear();
    }
};

void func(A* a)
{
    a->prepare_for_list_insertion();
}

int main()
{
    A a;
    func(&a); // calls A::prepare_for_list_insertion
    D d;
    // You need a cast to disambiguate the A base - either will do.
    func(static_cast<C*>(&d)); // calls D::prepare_for_list_insertion
    func(static_cast<B*>(&d)); // calls D::prepare_for_list_insertion
}