为什么我必须从继承的 class 中重新声明一个虚函数?
Why must I re-declare a virtual function from an inherited class?
我正在编写一个简单的 C++ 程序,但很难理解我遇到的编译器错误。这个问题是由于我试图从基础 class 创建派生的 class 引起的。我用相同的结构在下面发布了我的代码,但更改了名称。
BaseClass.h
#ifndef BASECLASS_H
#define BASECLASS_H
class BaseClass {
public:
BaseClass(void);
virtual int method1(void) = 0;
virtual int method2(void) = 0;
virtual float method3(void) = 0;
};
#endif // BASECLASS_H
DerivedClass.h
#ifndef DERIVEDCLASS_H
#define DERIVEDCLASS_H
#include "DerivedClass.h"
class DerivedClass: public BaseClass
{
public:
DerivedClass(void);
};
#endif // DERIVEDCLASS_H
DerivedClass.cpp
#include "DerivedClass.h"
DerivedClass::DerivedClass(void)
{
}
int DerivedClass::method1(void)
{
// TODO
}
int DerivedClass::method2(void)
{
// TODO
}
float DerivedClass::method3(void)
{
// TODO
}
尝试编译时,所有虚拟方法都出现以下错误:
no 'int DerivedClass::methodX()' member function declared in class 'DerivedClass'
只要我在 'DerivedClass.h' 中声明这些方法,错误就会消失,因为编译器现在可以识别这些方法。
但是,我很困惑。为什么有必要在 DerivedClass.h 中重新声明纯虚函数?当我#include DerivedClass.h 时,将自动包含 BaseClass.h,因此我假设我的 DerivedClass.cpp 应该完全了解这些方法。我做错了什么吗?
这样不行。您需要声明要定义的方法,无论它们是否重写虚方法。
这不仅仅是语言的不合理要求。没有这个,你将无法定义部分虚拟的 class,即,你可以拥有 BaseSubtype
,它具有 method1()
的通用实现,但需要从它派生的 classes 来实现 method2()
和 method3()
当您在派生 class 中声明方法时,您对编译器说:
I want to override this method in this class
所以如果你不在派生的 class 中声明一个方法,你说:
I don't want to override this method; derived class's implementation is the same as the one in the base class
在你的情况下,基础 class 将它们声明为纯虚拟的,因此在这种情况下可以解释为:
I don't want to implement this method in this class
如果你试图定义一个方法而不声明它,你就是在自相矛盾。编译器会检测到(以保护您免受自己的疏忽)。
为什么必须在基础 class 中派生重写虚方法的一个非常不直观的原因是 C++ 允许将 class 的不同部分放入不同的文件中,进入不同的翻译单位。
对于其他一些语言(我在看 Java 的方向),单个 class 必须放在一个文件中。对于 C++,情况并非如此。 class 在一个翻译单元中声明其某些方法,而在另一个翻译单元中声明其他方法是完全合法的,这些方法可以完全位于某个不同目录中的文件中。
每个这样的文件都是单独编译的。编译一个翻译时,C++ 编译器不知道任何其他翻译单元、任何其他文件可能包含相同内容的其他部分 class.
现在假设您可以从 class 声明中省略一个重写的虚拟方法。这就产生了一个直接的问题:当编译 class 的构造函数时,编译器有必要知道 class 是否覆盖了来自任何 superclasses 的任何虚拟方法,在为了正确 assemble 正在构建的 class 的虚拟 table 分派。如果没有显式声明,编译器无法知道其他翻译单元是否可能定义重写的虚拟方法。
这就是为什么必须在 class 的声明中显式包含重写的虚拟方法。结论:因为 C++ formally specifies phase 9, the linkage phase,在早期阶段进行实际编译,必须显式声明重写方法。
您应该覆盖所有基础 class 纯虚函数,以便能够实例化派生的 class。
- 您不能从派生 class 定义基 class 成员函数。
在您的示例中,您试图定义不是 DerivedClass 成员的 method1、method2 和 method3!您必须在派生 class 中自己声明它们。编译器不会为你做。
所以你的 Derivedclass.h 看起来像:
#ifndef DERIVEDCLASS_H
#define DERIVEDCLASS_H
#include "BaseClass.h"
class DerivedClass: public BaseClass
{
public:
DerivedClass(void);
virtual int method1(void); // not pure function
virtual int method2(void);
virtual float method3(void);
};
#endif // DERIVEDCLASS_H
我正在编写一个简单的 C++ 程序,但很难理解我遇到的编译器错误。这个问题是由于我试图从基础 class 创建派生的 class 引起的。我用相同的结构在下面发布了我的代码,但更改了名称。
BaseClass.h
#ifndef BASECLASS_H
#define BASECLASS_H
class BaseClass {
public:
BaseClass(void);
virtual int method1(void) = 0;
virtual int method2(void) = 0;
virtual float method3(void) = 0;
};
#endif // BASECLASS_H
DerivedClass.h
#ifndef DERIVEDCLASS_H
#define DERIVEDCLASS_H
#include "DerivedClass.h"
class DerivedClass: public BaseClass
{
public:
DerivedClass(void);
};
#endif // DERIVEDCLASS_H
DerivedClass.cpp
#include "DerivedClass.h"
DerivedClass::DerivedClass(void)
{
}
int DerivedClass::method1(void)
{
// TODO
}
int DerivedClass::method2(void)
{
// TODO
}
float DerivedClass::method3(void)
{
// TODO
}
尝试编译时,所有虚拟方法都出现以下错误:
no 'int DerivedClass::methodX()' member function declared in class 'DerivedClass'
只要我在 'DerivedClass.h' 中声明这些方法,错误就会消失,因为编译器现在可以识别这些方法。
但是,我很困惑。为什么有必要在 DerivedClass.h 中重新声明纯虚函数?当我#include DerivedClass.h 时,将自动包含 BaseClass.h,因此我假设我的 DerivedClass.cpp 应该完全了解这些方法。我做错了什么吗?
这样不行。您需要声明要定义的方法,无论它们是否重写虚方法。
这不仅仅是语言的不合理要求。没有这个,你将无法定义部分虚拟的 class,即,你可以拥有 BaseSubtype
,它具有 method1()
的通用实现,但需要从它派生的 classes 来实现 method2()
和 method3()
当您在派生 class 中声明方法时,您对编译器说:
I want to override this method in this class
所以如果你不在派生的 class 中声明一个方法,你说:
I don't want to override this method; derived class's implementation is the same as the one in the base class
在你的情况下,基础 class 将它们声明为纯虚拟的,因此在这种情况下可以解释为:
I don't want to implement this method in this class
如果你试图定义一个方法而不声明它,你就是在自相矛盾。编译器会检测到(以保护您免受自己的疏忽)。
为什么必须在基础 class 中派生重写虚方法的一个非常不直观的原因是 C++ 允许将 class 的不同部分放入不同的文件中,进入不同的翻译单位。
对于其他一些语言(我在看 Java 的方向),单个 class 必须放在一个文件中。对于 C++,情况并非如此。 class 在一个翻译单元中声明其某些方法,而在另一个翻译单元中声明其他方法是完全合法的,这些方法可以完全位于某个不同目录中的文件中。
每个这样的文件都是单独编译的。编译一个翻译时,C++ 编译器不知道任何其他翻译单元、任何其他文件可能包含相同内容的其他部分 class.
现在假设您可以从 class 声明中省略一个重写的虚拟方法。这就产生了一个直接的问题:当编译 class 的构造函数时,编译器有必要知道 class 是否覆盖了来自任何 superclasses 的任何虚拟方法,在为了正确 assemble 正在构建的 class 的虚拟 table 分派。如果没有显式声明,编译器无法知道其他翻译单元是否可能定义重写的虚拟方法。
这就是为什么必须在 class 的声明中显式包含重写的虚拟方法。结论:因为 C++ formally specifies phase 9, the linkage phase,在早期阶段进行实际编译,必须显式声明重写方法。
您应该覆盖所有基础 class 纯虚函数,以便能够实例化派生的 class。
- 您不能从派生 class 定义基 class 成员函数。
在您的示例中,您试图定义不是 DerivedClass 成员的 method1、method2 和 method3!您必须在派生 class 中自己声明它们。编译器不会为你做。
所以你的 Derivedclass.h 看起来像:
#ifndef DERIVEDCLASS_H
#define DERIVEDCLASS_H
#include "BaseClass.h"
class DerivedClass: public BaseClass
{
public:
DerivedClass(void);
virtual int method1(void); // not pure function
virtual int method2(void);
virtual float method3(void);
};
#endif // DERIVEDCLASS_H