我正在编写一些模板化的纯虚拟基类,这些基类是乘法继承的,并在此过程中发现了一个小的奇怪之处。关键是,如果您在两个基类中定义相同的方法,则从编译和工作正常继承,并且似乎只需要派生类中的单个定义。我很好奇这里幕后发生了什么,这是正确和有计划的行为还是危险的编译器疏忽?
有关说明性代码示例,请参见下文:
namespace
{
template <typename T_NumType>
class InheritFrom
{
public:
virtual void doSomething(const T_NumType& numType) = 0;
virtual void sharedMethod() = 0;
}; // class
class MultipleInheritor : public InheritFrom<int>, public InheritFrom<float>
{
public:
void doSomething(const int& numType) {}
void doSomething(const float& numType) {}
void sharedMethod() {} // one definition here
}; // class
}
int main(int argc, char** argv)
{
MultipleInheritor mult;
mult.doSomething(5);
mult.sharedMethod();
}
编辑:
下面的答案和查看 C++98 标准终于为我澄清了这一点。
从 10.3 开始:虚拟函数:
在任何格式良好的类中,对于每个 其中声明的虚函数 类或其任何直接或间接 基类有一个独特的最终 覆盖该函数的覆盖器 以及所有其他覆盖者 功能。
因此,这意味着对于任何虚函数,都将找到一个最终覆盖器。这是通过 10.2:成员名称查找中详述的规则完成的。
因此,在我介绍的案例中,确实有两个基类函数,并且由于成员名称查找,派生类中的单个函数被确定为两者的最终覆盖器。因此,我所拥有的是完美的格式,并且是C++编译器工作的逻辑结果。
这些函数具有不同的签名(一个采用 int,一个采用浮点数),因此实际上并不"相同"。
模板魔术有点混淆了这一点,但它就像你有foo(int)
和foo(float)
一样 - 这是两个不同的功能。你可以有foo(int) const
和foo(int)
,这也是两个不同的功能。
编辑:好的,让我解决实际问题(如您的评论中所述)。从技术上讲,它仍然没有歧义:每个版本的InheritFrom
都有自己的vtable,MultipleInheritor
有一个vtable。您可以选择限定sharedMethod
的任何父实现的范围(如 InheritFrom<int>::sharedMethod()
),但就调用方而言,类型 MultipleInheritor
的对象有一个 vtable,其中包含一个用于sharedMethod
的条目。
编辑:关键是你在子类中实现了sharedMethod
。如果它不是纯粹的并且没有MultipleInheritor
实现,就会有一个编译器错误,因为不清楚在 vtable 中的一个插槽中放入什么。
在派生类中使用一个函数定义覆盖两个同名的虚函数是 C++ 中多重继承的一个特征。
Bjarne Stroustrup在这里描述了一种可能使用虚函数实现的MI:C++的多重继承
基本上,MultipleInheritor
的 InheritFrom<int>
vtable 和 InheritFrom<float>
vtable 都会被修改,以便 sharedMethod
的两个条目都指向 MultipleInheritor::sharedMethod
。