多重继承和重复函数调用
我遇到类似于多重继承+虚函数混乱的情况。我在一个不太复杂的环境中复制了代码,以演示我感到困惑的地方。
我想知道 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
I have a situation similar to Multiple inheritance + virtual function mess. I've replicated the code in a less complex environment to demonstrate what I'm confused about.
I want to know how C is executing (but not acessing) both B1::method and B2::method, which then in turn executes the inherited methods.
The only way I can see this as working (correctly), is because the parent class is the one that propagates the function call to the sub classes, so it is accessing the vtables of Bx directly instead of through C.
In either case, is it safe, or undefined behavior, what pitfalls etc; and what is maybe a better way to do this.
#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;
}
output:
B1inhmethod in C
B2inhmethod in C
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为原因是 C 继承了 A 的两份副本,一份来自 B1,一份来自 B2。继承图如下所示:
当您创建 C 时,它会初始化 B1 和 B2 基类,这两个基类都会递归地初始化其 A 基类。这会导致两个不同的指针被添加到 A 的主列表中 - 指向 C 的 B1 基础对象的指针和指向 A 的 B2 基础对象的指针。它们都是同一个对象的一部分 - 即 C 实例 - 但因为有逻辑上涉及两个 A 基础对象,您将获得两个指针。然后,当您迭代 A 对象的列表时,您将找到 C 的 B1 组件和 C 的 B2 组件,因此两条消息都会打印出来。
如果这不是您想要的,请考虑研究虚拟继承,这将使 B1 和B2 对象共享一个 A 基础对象。这样,只有该对象的一个副本将被添加到主列表中。当然,如果这样做,你必须小心,因为那样你将需要 C 实现
method
以避免歧义;如果您没有定义它,则有两种method
实现,但显然都不是正确的调用方式。I think that the reason for this is that C inherits two copies of A, one from B1 and one from B2. The inheritance diagram looks like this:
When you create C, it initializes both the B1 and B2 base classes, both of which recursively initialize their A base class. This causes two different pointers to be added into A's master list - the pointer to the B1 base object of C and the pointer to the B2 base object of A. These are both part of the same object - namely the C instance - but because there are logically two A base objects involved you'll get two pointers. When you then iterate over the list of A objects, you'll find C's B1 component and C's B2 component, and hence both the messages print out.
If this isn't what you want, consider looking into virtual inheritance, which would let the B1 and B2 objects both share an A base object. That way, only one copy of the object would be added into the master list. Of course, you have to be careful if you do this, because then you would need C to have an implementation of
method
to avoid ambiguities; if you don't define it, there are twomethod
implementations where neither is clearly the right one to call.我假设这
实际上是对
B1method()
和B2method()
的重写,这只是一个拼写错误。我还假设您的问题是为什么调用这两个函数。由于类 C 继承自 B1 和 B2,因此它们的构造函数都将被调用,并且它们都将被添加到侦听器向量中。
那么由于应该调用哪个类方法
method
是没有歧义的,B1和B2仅继承自A并使用简单的多态性,B1Method和B2Method都会被调用。I assuming that
are in fact overrides of
B1method()
andB2method()
and that it's just a typo. And I'm also assuming that your question is why both of these are called.Since class C inherits from both B1 and B2, both of their constructor will get called and both of them will get added to the vector of listeners.
Then since there is no ambiguity from which class method
method
should be called, B1 and B2 only inherits from A and use simple polymorphism, Both B1Method and B2Method will get called.