为虚拟析构函数指定的冲突类型属性
Conflicting type attributes specified for virtual destructor
以下摘录之前是在 Borland C++、MSVC 和 OpenWatcom 下编译的:
class aaa {
virtual _fastcall ~aaa();
};
class bbb:public aaa {
};
它不能在 gcc/g++ (MinGW 4.8.0) 下编译。错误:
probz.cpp:7:7: 错误:为 'virtual bbb::~bbb()' 指定的类型属性冲突
class bbb:public aaa {
^
probz.cpp:3:20: 错误:覆盖 'virtual aaa::~aaa()'
virtual _fastcall ~aaa()=0;///不能抽象
^
很明显,没有bbb::~bbb()!
编辑
实际的class层级更大,有很多classes bbb继承自aaa,并且在它们之间有中间成员,即 bbb 扩展了 abb,它扩展了 aab,它扩展了 aaa。 aaa 确实有一个抽象的虚拟析构函数,它在中间 classes 中实现,但不是在叶子中。是的,我可以删除 __fastcall
属性并进行编译。我不能调整调用约定是gcc的限制吗?
__fastcall
是一个调用约定。
这是一个非标准功能:名称开头的双下划线表示它是具体实现。调用约定与系统和 CPU 体系结构密切相关。这似乎与 x86 32 位模式有关。
一些建议:
- 除非绝对需要(e.g.when 与预编译库交互或 extern dlls),否则您不应该为调用约定而烦恼。
- 现代编译器执行的优化级别不再需要此类手动调整。这同样适用于关键字
register
- 如果您的代码在某些平台上确实需要它,您应该预见到 header 中的一个
#define
并确保通过条件编译它在 platform/compilers 上没有定义在不相关的地方(对于 DLL,这种方法很常见,特定于库 #define
)。
- 所有派生的 class 中的调用约定应该相同,因此最好在基础 class 中声明。对于虚函数,这是隐含的强制要求!想象一下,您的基础 class 通过堆栈传递参数,而派生的 class 通过寄存器(快速调用)传递参数。现在,如果您通过基本 class 指针进行多态调用,您的编译器应该生成什么代码?如果两个派生的 classes 使用不同的调用约定会发生什么?
- 您不能假定调用约定是自动继承的:标准不作任何保证,此处
- 如果您必须指定调用约定,如果可能,最好使用外部链接说明符(例如
extern "C"
),因为这是唯一与调用约定相关的语义受标准支持。
附加信息:
以下摘录之前是在 Borland C++、MSVC 和 OpenWatcom 下编译的:
class aaa {
virtual _fastcall ~aaa();
};
class bbb:public aaa {
};
它不能在 gcc/g++ (MinGW 4.8.0) 下编译。错误:
probz.cpp:7:7: 错误:为 'virtual bbb::~bbb()' 指定的类型属性冲突 class bbb:public aaa { ^ probz.cpp:3:20: 错误:覆盖 'virtual aaa::~aaa()' virtual _fastcall ~aaa()=0;///不能抽象 ^
很明显,没有bbb::~bbb()!
编辑
实际的class层级更大,有很多classes bbb继承自aaa,并且在它们之间有中间成员,即 bbb 扩展了 abb,它扩展了 aab,它扩展了 aaa。 aaa 确实有一个抽象的虚拟析构函数,它在中间 classes 中实现,但不是在叶子中。是的,我可以删除 __fastcall
属性并进行编译。我不能调整调用约定是gcc的限制吗?
__fastcall
是一个调用约定。
这是一个非标准功能:名称开头的双下划线表示它是具体实现。调用约定与系统和 CPU 体系结构密切相关。这似乎与 x86 32 位模式有关。
一些建议:
- 除非绝对需要(e.g.when 与预编译库交互或 extern dlls),否则您不应该为调用约定而烦恼。
- 现代编译器执行的优化级别不再需要此类手动调整。这同样适用于关键字
register
- 如果您的代码在某些平台上确实需要它,您应该预见到 header 中的一个
#define
并确保通过条件编译它在 platform/compilers 上没有定义在不相关的地方(对于 DLL,这种方法很常见,特定于库#define
)。 - 所有派生的 class 中的调用约定应该相同,因此最好在基础 class 中声明。对于虚函数,这是隐含的强制要求!想象一下,您的基础 class 通过堆栈传递参数,而派生的 class 通过寄存器(快速调用)传递参数。现在,如果您通过基本 class 指针进行多态调用,您的编译器应该生成什么代码?如果两个派生的 classes 使用不同的调用约定会发生什么?
- 您不能假定调用约定是自动继承的:标准不作任何保证,此处
- 如果您必须指定调用约定,如果可能,最好使用外部链接说明符(例如
extern "C"
),因为这是唯一与调用约定相关的语义受标准支持。
附加信息: