是否需要多重继承
Is multiple inheritance needed?
我有一个这样的情况:
class A {
virtual void f() { /*some default impl here*/}
virtual void g() { /*some default impl here*/}
};
class B : public A {
virtual void f() { /* do some specific stuff and call parent's f()*/}
virtual void g() { /* do some specific stuff and call parent's g()*/}
};
class C : public A {
virtual void f() { /* do some specific stuff and call parent's f()*/}
virtual void g() { /* do some specific stuff and call parent's g()*/}
};
class mixed /* I don't know how to derive*/ {
virtual void f() { /* call B::f()*/}
virtual void g() { /* call C::g()*/}
};
我这里考虑的是多重继承。即由B
和C
衍生出mixed
。但也有一些已知的问题(例如,钻石问题)。
另一个解决方案是组合。
但正确的解决方法是什么,请告诉我:)
提前感谢!
一些已知的问题(例如,Diamond问题)。
第一:除非你显式地创建一个,否则没有菱形图案。
class mixed: public B, public C
这将使混合继承B和c,每个都有自己的显式A(没有菱形)。
由于B和C都有从A派生的虚成员,因此应该调用哪一个变得不明确,但您已经通过mixed
中所有虚成员的显式定义解决了这个问题(因此问题解决了)。
void mixed::f() { B::f();} // works fine.
现在即使你显式地创建了一个菱形。
注意:菱形图案不正常出现。菱形模式是一个必须显式做出的设计决策,您可以使用它来解决某些类型的问题(通过使用虚拟继承)。
class B: public virtual A ...
class C: public virtual A ...
class mixed: public B, public C ...
你还是没有问题。因为mixed::f()
只使用B
分支(然后是A),而mixed::g()
只使用C
分支(然后是A)。
即使A
有自己的状态(虽然这可能是一个坏主意,通常最好使用接口作为虚拟基类),那么我们没有问题,因为mixed::f()
和mixed::g()
只调用一个子函数(问题开始发生,如果他们调用两边,A
的状态都被两个调用改变。
另一个解决方案是组合。
也可以。
class mixed: public A
{
B b;
C c;
public:
virtual void f() override {b.f();}
virtual void g() override {c.g();}
....
};
但是正确的解决方案是什么
没有正确的解决方案。这在很大程度上取决于你没有提到的细节(比如a的细节是什么)。
BUT一般建议是选择复合而不是继承,但这只是一般建议的细节,将始终归结为要解决的实际问题。
每个方法在调用父类之前都必须"做一些事情",这是导致问题的原因。
一个解决方案是将A
和B
作为mixed
类的成员。然后你可以在mixed::f()
和mixed::g()
f()
和g()
创建一个基类base
。mixed
可以继承它,A
、B
和C
也可以。当你引用组合我想你可能正在寻找这样的东西。(对不起,这是一大堆代码,但它真的很直接。)
#include <iostream>
struct A
{
virtual void
f()
{
std::cout << __PRETTY_FUNCTION__ << 'n';
}
virtual void
g()
{
std::cout << __PRETTY_FUNCTION__ << 'n';
}
// Don't forget the virtual destructor.
virtual ~A() noexcept = default;
};
struct B : virtual A
{
virtual void
f() override
{
std::cout << __PRETTY_FUNCTION__ << 'n';
A::f();
}
virtual void
g() override
{
std::cout << __PRETTY_FUNCTION__ << 'n';
A::g();
}
};
struct C : virtual A
{
virtual void
f() override
{
std::cout << __PRETTY_FUNCTION__ << 'n';
A::f();
}
virtual void
g() override
{
std::cout << __PRETTY_FUNCTION__ << 'n';
A::g();
}
};
struct D : virtual B, virtual C
{
virtual void
f() override
{
std::cout << __PRETTY_FUNCTION__ << 'n';
B::f();
}
virtual void
g() override
{
std::cout << __PRETTY_FUNCTION__ << 'n';
C::g();
}
};
int
main()
{
D d {};
d.f();
std::cout << 'n';
d.g();
}
override
是c++ 11的一个特性,它可以让编译器检查你实际上是否重写了。使用它是一种良好的实践,但如果编译器不支持它,则不需要使用它。__PRETTY_FUNCTION__
是一个GCC扩展,用于获取命名当前函数签名的字符串字面值。标准c++有__func__
,但在这里用处不大。如果你的编译器没有类似__PRETTY_FUNCTION__
的功能,你可以自己键入字符串。
virtual void D::f()
virtual void B::f()
virtual void A::f()
virtual void D::g()
virtual void C::g()
virtual void A::g()
它可以工作,但我不认为这是漂亮的代码。组合可能是更好的解决方案。
这是虚拟继承的另一种选择:使用CRTP将B
和C
的功能混合到M
中,同时共享一个公共A
,而没有虚表的开销。
#include <iostream>
struct A
{
int a;
};
template <typename T>
struct B
{
A *get_base_a() {return static_cast<T*>(this);}
void print_a() {std::cout << get_base_a()->a << 'n';}
};
template <typename T>
struct C
{
A *get_base_a() {return static_cast<T*>(this);}
void print_a() {std::cout << get_base_a()->a << 'n';}
};
struct M : A, B<M>, C<M>
{
};
int main()
{
M m;
m.a = 1;
m.B::print_a();
m.C::print_a();
return 0;
}
但是请注意,您不能将M*
传递给期望B*
或C*
的函数。
- 关于C++中具有多重继承"this"指针的说明
- 在运行时检查继承是否只有一种类型和 void*
- C++中模板化异常类的多重继承
- 虚拟继承中是否存在多重继承?
- 如何在 c++ 多重继承中调用父非虚函数?
- 多重继承相同的方法名,没有歧义
- 使用enable_if解决多重继承歧义
- 多重继承导致虚假的模糊虚拟函数过载
- 多重继承和访问不明确的元素
- C++ 多重继承:使用基类 A 的实现实现基类 B 的抽象方法
- QScopedPointer 是否隐藏了多重继承
- c++:多态性+多重继承顺序.继承顺序是否重要
- 这个多重继承的例子在C++中是否可以接受
- 添加插件 SDK - 是否多重继承
- 在 OMNeT++ 中使用多重继承时是否存在任何已知问题
- 是否有可能用Java接口取代C++的多重继承
- 如果QObject是从direct派生的,那么使用“虚拟”多重继承是否安全?
- 多重虚拟继承是否涉及虚拟函数的后期绑定式继承
- 是否需要多重继承
- 检查类型是否使用多重继承