函数定义中的纯说明符

40

在使用GCC编译时,我遇到了error: pure-specifier on function-definition的错误,但是在使用VS2005编译相同的代码时没有出现此问题。

class Dummy {   
  //error: pure-specifier on function-definition, VS2005 compiles 
  virtual void Process() = 0 {};
};

但当这个纯虚函数的定义不是内联时,它就可以工作:

class Dummy
{
  virtual void Process() = 0;
};
void Dummy::Process()
{} //compiles on both GCC and VS2005

这个错误是什么意思?为什么我不能内联执行?像第二个代码示例中所示,规避编译问题是否合法?


1
顺便说一下,你多了一个不必要的分号。 - QuentinUK
6个回答

40

好的,我刚学到了一些东西。一个纯虚函数必须声明如下:


class Abstract 
{
public:
   virtual void pure_virtual() = 0;
};

虚函数可以有实体,但在声明时包含实体是不允许的。这意味着想要有实体,纯虚函数必须在类外定义。请注意,即使具有实体,该函数仍然必须被任何继承自Abstract的具体类重载。如果需要,它们只能显式调用Abstract::pure_virtual()

详见此处


2
如果你需要的话,是的,应该有一个。拥有一个是完全合法的。 - anon
但是如果有了函数体,它只会成为一个虚函数。那么一个带有函数体的纯虚函数应该做什么呢? - Martin Tilsted
1
@Martin 可能什么都不会发生 - 如果你声明了一个纯虚析构函数(例如),你必须给它一个实现。 - anon
@MartinTilsted 不是很准确,可以参考https://dev59.com/K2035IYBdhLWcg3wVuh1。 - Melebius

20

C++标准,10.4/2:

一个函数声明不能同时提供纯虚指定符和定义。


这不是规范,而是来自一份笔记。 - Columbo
@Columbo 嗯,根据ISO/IEC指令第2部分§6.5.1的规定,注释根本不应包含任何权限。虽然这个注释明显包含了一个权限,这让我感到困惑。但现代的GCC和Clang都不允许这样做,他们违反了标准吗? - Paul
专业提示:请阅读我的答案。这个注释是正确的,但是要“证明”它的话,就必须展示语法规则。 - Columbo

13

这个语法:

virtual void Process() = 0 {};

这不是合法的C ++,但受VC ++支持。标准为什么不允许这样做从来没有显而易见过。您的第二个示例是合法的。


4

在C++中,纯虚函数的定义在声明中没有定义。

你的第二个代码块并没有避免编译器问题。它是按照预期实现纯虚函数的方式。

需要问的问题是,如果您打算有默认实现,为什么需要声明它为纯虚函数?


2
纯虚函数可以有定义。想想纯虚析构函数 - 必须被定义。 - Paul
1
请告诉我一个纯虚析构函数的目的是什么? - Amardeep AC9MF
1
当您不希望类被实例化且没有其他纯虚函数候选项时,可以将析构函数设为纯虚函数。我同意这是一个相当罕见的需求。 - anon
3
作为代码的作者,我来回答这个问题:默认实现是为派生类提供帮助而设计的。它们应该调用默认实现,但需要明确地这样做。这是为了确保调用默认实现是一个有意识的设计,而不是一种无意识的行为。就像转换/构造函数中的“explicit”关键字一样。它并没有提供任何新的可能性,但可以帮助避免错误。 - Suma

3

这是语法上不允许的 - 只有在声明而非定义中才会出现可以包含纯说明符, 即成员声明器的声明符。[class.mem]

成员声明:
         属性说明符序列可选 类型说明符序列可选 成员声明器列表可选 ;
         函数定义
         [...]

成员声明器列表:
         成员声明器
         成员声明器列表 , 成员声明器

成员声明器:
         声明符 虚说明符序列可选 纯说明符可选
         声明符 大括号或等于初始化项可选
         标识符可选 属性说明符序列可选 : 常量表达式

函数定义的语法不包括纯说明符,[dcl.fct.def.general]:

函数定义:
     属性说明符序列可选 类型说明符序列可选 声明符 虚说明符序列可选 函数体


0
你肯定可以为纯虚函数提供一个函数体,这个函数将被抽象类 vtable 指向。否则,同样的插槽将指向编译器特定的陷阱函数,比如 GCC 的 __cxa_pure_virtual。当然,标准中没有任何关于此的内容。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接