19

假设我有以下代码:

class Iinterface
{
  virtual void abstractFunction()=0;
};

class Derived : public Iinterface
{
  void abstractFunction(); // Do I need this line?
};

Derived::abstractFunction()
{
  // implementation here
}

如果我不添加有问题的行,我会得到编译错误,它说abstractFunction没有在Derived. 我正在使用 VS 2008。
我不知道为什么我需要这个特定的行(不要将它与在类声明之外提供的函数定义混淆),只要我从Iinterface它继承就应该很明显我已经abstractFunction声明. 这是 Visual Studio 的问题还是由 C++ 标准强制执行?

4

4 回答 4

8

如果在所有派生类中都隐含了纯虚拟基函数的声明,那么您永远不会有一个相对于纯虚拟基函数保持抽象的派生类。相反,所有派生类都会产生链接器错误。这将是非常违反直觉和令人困惑的,并且会降低语言的表达力。

此外,它甚至没有意义:派生类是否是抽象的问题必须在编译时无处不在。覆盖器的实现通常仅在一个翻译单元中提供,因此不可能将您实际上意味着要覆盖该函数的事实传达给程序的其余部分。

于 2012-11-19T07:22:25.123 回答
2
  1. :如果你想创建一个对象class Derived
  2. :如果你想保持class Derived抽象
  3. :如果有一个中间类已经覆盖了函数,
    例如,Iinterface并且Derived有一个class Intermediate已经覆盖了abstractFunction();所以现在可以选择class Derived覆盖相同的

编辑:使用更改的问题标题,

为什么我必须在 C++ 的派生类中重新声明被覆盖的函数?

这是因为 C++ 编译器语法要求(或或文件)的每个成员函数都class必须namespaceclass(或namespace或文件)主体内声明。无论是virtual正常功能还是正常功能。
没有充分理由仅仅为virtual函数打破这种一致性。

于 2012-11-19T07:10:23.003 回答
1

以 an 结尾的函数=0称为 a deleted function,当您不希望使用某些构造函数的对象(例如unique_ptr具有已删除的副本 ctor)的对象时,这很有用。

如果一个virtual函数被删除,那么按照标准,这个类就变成了一个抽象类型。因为在大多数情况下,类的原型和类的函数体位于不同的文件中,这意味着除非您在原型中明确概述您要覆盖已删除的虚函数,否则您不会覆盖已删除的虚函数。一旦编译器在完全不同的文件中看到实现,编译器不应该只是简单地推断出您打算将函数放在那里。

请记住,原型/实现的想法并不是编写代码的唯一方法,您还可以将实现放在类中(如果代码足够小并且您想要内联函数,则可以这样做。)然后做您需要再次明确覆盖已删除的虚拟功能。因此,因为无论如何您都需要覆盖它,所以您需要在原型中显式覆盖它是非常有意义的。否则该功能仍会被删除。

举个具体的例子:假设你有一个 List.hpp、List.cpp 和 main.cpp

在 List.hpp 中有一个抽象类和一个从抽象类继承的常规类。主要是你#include "List.hpp"而不是 List.cpp,对吧?所以编译器不知道该文件中的内容(直到它尝试编译它。)如果您没有覆盖已删除的虚函数,那么编译器会认为您只是在尝试实例化一个抽象类并引发错误。

另一方面,如果你正在编译 List.cpp,那么编译器也会抛出一个错误,这一次抱怨你试图编写的函数实际上并没有被定义。因为Base::deletedFunction()不同于Derived::deletedFunction().

于 2012-11-19T07:19:29.330 回答
0

是的,纯虚函数的全部意义在于强制您在派生类中覆盖它;此声明必须在 C++ 中显式

于 2012-11-19T07:07:12.100 回答