为什么继承不能隐式定义

3

这个问题可能以前已经有人回答过,但我找不到相关的解释。

我正在尝试理解C++中的继承,但是由于我的背景是C#,我似乎无法理解以下情况的原因:

Foo.h

class Foo {
    virtual void DoSomething();
}

class Bar : Foo { }

Bar.cpp

#include "Foo.h"    
void Bar::DoSomething() 
{
    //Compiler error C2509 - member function not declared in 'Bar'
}

由于DoSomething是一个纯虚函数,那么它不会自动成为Bar的一部分吗?

如果我有很多不同的类继承自Foo,我真的需要在每个类中显式声明DoSomething吗?

C++中还有哪些构造可以处理这种情况?


我可以提个建议吗?为了您自己的心理健康,请将Bar.c重命名为Bar.cpp。 - KevinDTimm
5
“DoSomething()” 在“Foo”、“Bar” 或其他地方并非纯虚函数,它只是虚函数。 - WhozCraig
你在哪里告诉编译器 Bar 也不应该是抽象的? - dyp
@WhozCraig 谢谢,我现在明白你的意思了。不过在我的情况下它并不影响结果。 - Rotem
@DyP 我假设实现 Bar::DoSomething 就是这样做的。 - Rotem
显示剩余7条评论
3个回答

10

C++语言采用C的独立编译原则,这意味着C++程序中的所有编译单元应该能够彼此完全独立地编译。它们会在编译器完成工作后链接到最终的程序中。

对于类而言,为了能够独立编译每个编译单元,编译器必须通过查看该类的定义(通常放置在头文件中的部分)来建立对该给定类足够全面的理解。编译一个编译单元时,编译器必须知道DoSomethingBar中被覆盖,并且void Bar::DoSomething()的定义存在于其他某个编译单元中。为了实现这一点,类定义必须包含所有类成员函数的声明。

关于“纯虚函数”的概念,您的推论让我完全不明白。首先,在您的代码示例中它并不是纯虚的(显然您只是忘记了= 0部分)。其次,仅因为基类函数是纯虚的,并不意味着派生类函数就应该是非纯的。很可能Bar也应该是一个抽象类。这取决于您的意图,而编译器并不知道。


谢谢。你上一段中的错误假设是我问题的根源。 - Rotem

3
< p > Bar 的定义是大多数代码所需了解的全部内容。其他翻译单元将不会看到 "Bar.cpp",但仍需要生成正确的内存表示形式,包括 Bar 的虚函数表(vtable),以及 Bar 实例。这意味着它们需要知道 Bar 是否真正覆盖了 Foo::DoSomething,因为内存表示因此而异。


2

是的,你需要明确声明这个方法。如果你来自C#,你会注意到C++在很多方面都不会“牵着你的手”。我并不是有意冒犯,但C++强制你在所有做的事情上都变得非常明确。


谢谢。只是为了明确,您的意思是,如果您有一个抽象的Foo类,就像我的例子一样,而且您想要10个不同的专门的Bar类,您会显式地声明每一个吗?我只是假设会有更简单的方法。 - Rotem
是的,你需要在它们每一个中明确地声明它。 - Will Custode

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