c++ - 为虚拟析构函数指定的冲突类型属性

标签 c++ inheritance g++ virtual-functions calling-convention

以下摘录之前是在 Borland C++、MSVC 和 OpenWatcom 下编译的:

class aaa {
    virtual _fastcall ~aaa();
};

class bbb:public aaa {
};

它不能在 gcc/g++ (MinGW 4.8.0) 下编译。错误:

probz.cpp:7:7: error: conflicting type attributes specified for 'virtual bbb::~bbb()'
 class bbb:public aaa {
       ^
probz.cpp:3:20: error:   overriding 'virtual aaa::~aaa()'
   virtual _fastcall ~aaa()=0;///can't be abstract
                     ^

显然,没有 bbb::~bbb()!

编辑

实际的类层次结构更大,有很多bbb类继承自aaa,中间还有一些中间成员,即bbb extends abb,它extends aab,延伸 aaa。 aaa 确实有一个抽象的虚拟析构函数,它在中间类中得到实现,但在叶子中没有。是的,我可以删除 __fastcall 属性并进行编译。我不能调整调用约定是 gcc 的限制吗?

最佳答案

__fastcall是一个调用约定。

这是一个非标准功能:名称开头的双下划线表示它是特定于实现。调用约定与系统和 CPU 架构密切相关。这似乎与 x86 32 位模式有关。

一些建议:

  • 除非绝对需要(例如,当与预编译库或 extern dlls 交互时),否则您不应该为调用约定而烦恼。
  • 现代编译器执行的优化级别不再需要此类手动调整。这同样适用于关键字 register
  • 如果您的代码在某些平台上确实需要它,您应该在其中一个 header 中预见到 #define 并确保通过条件编译它在不相关的平台/编译器上没有定义(对于 DLL,这种方法很常见,使用特定于库的 #define)。
  • 所有派生类的调用约定应该相同,因此最好在基类中声明。对于虚函数,这是一个隐含的强制要求!想象一下,您的基类通过堆栈传递参数,派生类通过寄存器传递参数(fastcall)。现在,如果您通过基类指针进行多态调用,您的编译器应该生成什么代码?如果两个派生类使用不同的调用约定会怎样?
  • 您不能假设调用约定是自动继承的:标准在此处不做任何保证
  • 如果您必须指定调用约定,请尽可能首选外部链接说明符(例如 extern "C" ),因为这是唯一与调用约定相关的语义受标准支持。

附加信息:

关于c++ - 为虚拟析构函数指定的冲突类型属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28385849/

相关文章:

c++ - 如何确保一个函数只被调用一次

C++构造函数差异

c# - 从派生类设置只读对象

java - Java 中通过接口(interface)重写的替代方案是什么?

c++ - 如何在 gdb 中将 void 指针转换为 unique_ptr<T>?

c++ - 尽管项目很小,但 g++ 仍会生成大型二进制文件

c++ - 使用 GCC 输出注释和注释的中间文件

c++ - <> 中包含的文件找不到 ""中包含的文件

c++ - 如何将信息从启动器传递到我的程序?

java - 迭代反射的子类,变量似乎没有阴影,IntelliJ 似乎有冲突