虚拟继承 - gcc 与 vc++

Posted

技术标签:

【中文标题】虚拟继承 - gcc 与 vc++【英文标题】:Virtual inheritance - gcc vs. vc++ 【发布时间】:2009-09-17 07:13:51 【问题描述】:

我对 Visual Studio 2008 的虚拟继承有疑问。

考虑以下示例:

#include<iostream>

class Print 
    public:

    Print (const char * name) 
        std::cout << name << std::endl;
    
;

class Base : public virtual Print 
    public:

    Base () : Print("Base") 
;

class A : public Base 
    public:

    A () : Print("A") 
;

class B : public A 
    public:

    B () : Print("B") 
;

int main (int argc, char** argv) 
    A a; // should print "A"
    B b; // should print "B"
    return 0;

如果我在我的 linux 机器上使用 gcc,这段代码编译得很好。 但是,如果我尝试使用 Visual Studio 在 Windows 上构建相同的内容,则编译失败并显示错误消息“错误 C2614:'B':非法成员初始化:'Print' 不是基础或成员。”

为什么这不起作用?

【问题讨论】:

代码在 VS2008 下编译并且对我来说很好。 错误出现在哪一行? 在 Visual C++ 2008 SP1 上按预期工作。 【参考方案1】:

来自标准 [class.base.init]:“除非 mem-initializer-id 命名构造函数类的非静态数据成员或该类的直接或虚拟基类,否则 mem-initializer 是格式错误的。 "

显然 gcc 将您的案例解释为合法,因为 PrintB 的非直接但虚拟基础,但是 MSVC 2008 没有将 Print 视为 B 的虚拟基础 - 仅是虚拟基础非虚拟基地的基地。 (顺便说一下,您的示例是在 VS2005 上编译的,所以这是一个令人惊讶的行为变化。)

我倾向于 gcc 的解释是正确的(否则“直接基础”的措辞就足够了)。

要解决此问题,您可以虚拟地从Print 派生B。由于Print 已经是A 的虚拟基础,这对类布局或基础类Print 子对象的数量没有任何整体影响。

【讨论】:

感谢您引用标准。正如您和其他人所指出的,代码可以在各种 VS 安装上编译。因此,我在错误消息刚刚消失的另一台机器上重新编译了相同的代码。也许我机器上的 VS 安装已损坏。【参考方案2】:

您使用的是什么版本的 Visual Studio?您发布的代码在 VC 9(特别是 15.00.21022.08)和 VC 6 以及其他一些编译器上对我来说很好。

你确定 class B 在 Visual Studio 中看起来不是这样吗:

class B   //  note: no base class
    public:

    B () : Print("B") 
;

【讨论】:

不,代码就像我的例子一样。请参阅我对另一个答案的评论。 哪个版本的编译器会失败?更改项目的“Suppress Startup Banner”属性或使用命令行获取该信息。

以上是关于虚拟继承 - gcc 与 vc++的主要内容,如果未能解决你的问题,请参考以下文章

这种“方法注入”的虚拟继承使用模式是一种已知的范例吗?

对于从虚拟基类继承的虚函数,什么是“虚拟thunk”?

C++菱形继承问题与虚拟继承原理

C++菱形继承问题与虚拟继承原理

C++之继承总结(继承的定义与格式,赋值转换,默认成员函数,菱形继承及菱形虚拟继承)

C++-继承-菱形继承-菱形虚拟继承-虚函数表