如何使用多重继承实现多态行为
How do you implement polymorphic behaviour with multiple inheritance?
我从未使用过多重继承,但最近读到它时,我开始思考如何在代码中实际使用它。当我正常使用多态性时,我通常通过创建声明为基类指针(如)的新派生实例来使用它
BaseClass* pObject = new DerivedClass();
以便在派生类上调用虚拟函数时获得正确的多态行为。通过这种方式,我可以拥有不同多态类型的集合,它们通过虚拟函数管理自己的行为。
当考虑使用多重继承时,我考虑的是相同的方法,但如果我有以下层次,我该如何做到这一点
class A {
virtual void foo() = 0;
};
class B : public A {
virtual void foo() {
// implementation
}
};
class C {
virtual void foo2() = 0;
};
class D : public C {
virtual void foo2() {
// implementation
}
};
class E : public C, public B {
virtual void foo() {
// implementation
}
virtual void foo2() {
// implementation
}
};
有了这个层次结构,我可以创建一个新的E类实例作为
A* myObject = new E();
或
C* myObject = new E();
或
E* myObject = new E();
但是如果我将其声明为CCD_ 1,那么我将失去类C和D继承层次结构的多态性。类似地,如果我把它声明为C*
,那么我就失去了类A和类B的多态性。如果我将其声明为E*
,那么我就无法像通常那样获得多态行为,因为对象不是通过基类指针访问的。
所以我的问题是解决这个问题的办法是什么?C++是否提供了一种可以解决这些问题的机制,或者指针类型必须在基类之间来回转换?当然这是相当麻烦的,因为我不能直接做下面的
A* myA = new E();
C* myC = dynamic_cast<C*>(myA);
因为强制转换将返回一个NULL指针。
通过多重继承,您可以使用多种不同方式查看单个对象。例如:
class door {
virtual void open();
virtual void close();
};
class wood {
virtual void burn();
virtual void warp();
};
class wooden_door : public wood, public door {
void open() { /* ... */ }
void close() { /* ... */ }
void burn() { /* ... */ }
void warp() { /* ... */ }
};
现在,如果我们创建了一个wooden_door对象,我们可以将其传递给一个期望与door对象一起工作的函数(对door对象的引用或指针),或者一个希望与wood
对象一起工作(同样是对CCD_4对象的指针或引用)的函数。
的确,多重继承不会让使用door
的函数突然拥有使用wood
的任何新功能(反之亦然),但我们并不期望如此。我们所期望的是能够将我们的木门视为一扇可以打开和关闭的门,或者视为一块可以燃烧或弯曲的木头——这正是我们所得到的。
在这种情况下,类A
和C
是接口,E
实现两个接口。(通常,您不会有中间类A*
0和D
。)有几种方法可以解决这个问题。
最常见的可能是定义一个新接口,它是一个和A
和C
的
class AandC : public A, public C {};
并由此导出CCD_ 14。然后,您通常会通过AandC*
,将其无差别地传递给采用A*
或CCD_ 18。需要同一对象中的两个接口的函数将处理用CCD_ 19。
如果接口A
和C
在某种程度上是相关的,比如C
提供某些A
(但不是全部)可能想要的额外设施则A
具有getB()
功能可能是有意义的,返回C*
(如果对象不支持,则返回空指针CCD_ 27接口)。
最后,如果您有和多个接口的混合,那么最干净的解决方案是维护两个独立的层次结构,一个用于接口,以及另一个与实现部分:
// Interface...
class AandC : public virtual A, public virtual C {};
class B : public virtual A
{
// implement A...
};
class D : public virtual C
{
// implement C...
};
class E : public AandC, private B, private D
{
// may not need any additional implementation!
};
(我很想说,从设计的角度来看接口应该始终是虚拟的,以允许未来,即使现在不需要。然而,在实践中无法提前预测这种用途的情况相当罕见。)
如果你想了解更多关于这类事情的信息,你可能想阅读巴顿和纳克曼。这本书现在已经过时了(它描述C++98之前),但大多数信息仍然有效。
这应该能在中工作
A* myA = new E();
E* myC = dynamic_cast<E*>(myA);
myC->Foo2();
C
不能转换为A
,因为它不是A
;则它只能向下投射到CCD_ 31或CCD_。
使用A*
,您可以生成E*
,通过它,您总是可以显式地说C::foo()
之类的话,但是的,A
无法隐式调用C
中可能有重写或没有重写的函数。
在这种奇怪的情况下,模板通常是一个很好的解决方案,因为它们可以允许类表现为具有公共继承,即使它们没有。例如,您可以编写一个模板,该模板可以与任何可以调用foo2()
的模板一起使用
- 如何在这个简单的最小示例中实现多态性?
- 使用连续内存实现多态性
- 实现后期多态性的最佳方法
- 将多态性与运算符 + 重载模板化类结合使用.如何实现基类?
- 为实体组件系统实现多态组件
- 多态性实现
- 在 C++ 中实现多态性有哪些不同的方法
- 具有多态数据的容器的常见实现是什么
- 可以使用不同的实现文件来实现多态性吗
- 如何使用多重继承实现多态行为
- 类中的多态函数,实现抽象类
- C++ 具有多父多态层次结构的 VTable 实现
- 如何在嵌套类中实现多态性
- 如何利用多态性实现数据本地化
- 一个具有多态性的2-3树的设计与实现
- 如何在多态性c++中实现这个类
- 如何实现几个函数的编译时多态性
- 我们可以通过const函数实现多态性吗
- 用排序函数实现多态性
- c++私有多态实现设计