多重继承和重复的函数调用

时间:2011-02-10 03:58:52

标签: c++ inheritance event-handling virtual multiple-inheritance

我的情况类似于Multiple inheritance + virtual function mess。我在一个不太复杂的环境中复制了代码,以展示我对此感到困惑的内容。

我想知道C是如何执行(但不是访问)B1 :: method和B2 :: method,然后又执行继承的方法。

我能看到它正常工作的唯一方法是,因为父类是将函数调用传播到子类的,所以它直接访问Bx的vtable而不是通过C。

在任何一种情况下,它是安全的,还是不明确的行为,有什么陷阱等;什么是更好的方法来做到这一点。

#include <iostream>
#include <vector>

class A {
    static std::vector<A*> listeners;
public:
    static void propagate();
protected:
    A() {
        listeners.push_back(this);
    }
    ~A() {
        for (std::vector<A*>::iterator it = listeners.begin(); it != listeners.end(); ++it) {
            if (*it == this) {
                listeners.erase(it);
                break;
            }
        }
    }
    virtual void method()=0;
};

std::vector<A*> A::listeners;

void A::propagate() {
    for (unsigned int i=0; i < listeners.size(); ++i) {
        listeners[i]->method();
    }
}

class B1 : public A {
protected:
    B1() {}
    ~B1() {}
    void method() {
        B1inhmethod();
    }
    virtual void B1inhmethod() {}
};
class B2 : public A {
protected:
    B2() {}
    ~B2() {}
    void method() {
        B2inhmethod();
    }
    virtual void B2inhmethod() {}
};

class C : public B1, public B2 {
public:
    C() {}
    ~C() {}
    void B1inhmethod() {
        std::cout << "\nB1method in C";
    }
    void B2inhmethod() {
        std::cout << "\nB2method in C";
    }
};

int main() {
    C myclass;
    A::propagate();
    return 0;
}

输出:

B1inhmethod in C
B2inhmethod in C

2 个答案:

答案 0 :(得分:2)

我认为原因是C继承了A的两个副本,一个来自B1,一个来自B2。继承图如下所示:

A       A
|       |
B1     B2
  \   /
   \ /
    C

当你创建C时,它会初始化B1和B2基类,这两个基类都递归地初始化它们的A基类。这导致两个不同的指针被添加到A的主列表中 - 指向C的B1基础对象的指针和指向A的B2基础对象的指针。这些都是同一对象的一部分 - 即C实例 - 但是因为那里在逻辑上是两个基础对象涉及你会得到两个指针。当你迭代A对象列表时,你会发现C的B1组件和C的B2组件,因此两个消息都打印出来。

如果这不是您想要的,请考虑查看virtual inheritance,这将使B1和B2对象共享一个A基础对象。这样,只有一个对象副本将被添加到主列表中。当然,如果你这样做,你必须要小心,因为那时你需要C实现method以避免含糊不清;如果你没有定义它,有两个method实现,其中两个都不是正确的调用。

答案 1 :(得分:0)

我假设

void B1inhmethod() {
    std::cout << "\nB1inhmethod in C";
}
void B2inhmethod() {
    std::cout << "\nB2inhmethod in C";
}

实际上是B1method()B2method()的覆盖,而这只是一个错字。而且我也假设你的问题是为什么这两个都被调用了。

由于C类继承自B1和B2,因此它们的构造函数都将被调用,并且它们都将被添加到侦听器的向量中。

然后,由于没有应该调用类方法method的歧义,B1和B2只从A继承并使用简单的多态,B1Method和B2Method都将被调用。