我的情况类似于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
答案 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都将被调用。