2012-05-04 8 views
3

当我有这样的事情:为什么链接程序在虚拟情况下给我一个错误,而不是在非虚拟情况下?

class A 
{ 
    virtual void rat(); 
}; 

class B : public A 
{ 
    virtual void rat() { ; } //implemented! 
}; 

int main(int argc, char **argv) 
{ 
    A *a = new B; 
    delete a; 
} 

我得到的链接错误:

,除非我制造基地老鼠纯虚。

然而,当我有这样的:

class A 
{ 
    public: 
    void rat(); 
}; 

int main(int argc, char **argv) 
{ 
    A a; 
} 

编译没有问题,不给我一个未定义的引用链接错误,除非我明确地尝试调用函数老鼠在我的主(a.rat();)。什么是未实现的基类虚函数的规则,但是,在派生类中实现,就像在第一个失败的代码片段中一样?

+0

另请参见:http://stackoverflow.com/questions/4145915 –

回答

5

当两个类都定义了虚拟函数时,C++编译器需要为类AB构建vtables。要构建A的vtable,编译器需要A::rat() - 这是引用来自的地方。

A没有虚函数时,从任何地方都没有对A::rat的引用,因此您不会收到编译错误。

正如我确信你知道的,你可以通过使A::rat为纯虚拟来修正这个错误,从而为vtable提供所需的值(在这种情况下,值为零)。

+0

为了防止宫陈不知道如何声明纯虚拟的东西,我想我会添加它。 virutal void rat()= 0; –

4

需要实现每个非纯虚函数。

class A 
{ 
    public: void rat(); 
}; 

int main(int argc, char **argv) 
{ 
    A a; 
} 

上面的代码完全是一个不同的场景。在你不调用非纯虚函数的情况下,你不会得到编译器/链接器错误,因为尽管它是在类定义中声明的,但它根本没有调用它。

现在在下面的代码中,编译器只检查是否存在名为rat()的成员函数,或者不在A中。

A a; 
a.rat(); // Compiler passes. But linker bombs. 

现在你应该得到一个链接错误。

2

因为A::rat()纯虚拟的,它必须的实现。

+0

准确,但更多的信息会使这个更好的答案。 –

+0

@MooingDuck:什么样的信息?我可以编辑。 –

+0

也许纯粹的虚拟手段,为什么它是相关的,以及为什么第二个例子在第一个没有的时候编译。 –

2

标准法律术语是使用ODR:必须定义使用ODR的函数,否则它是错误的。

将函数标记为ODR的规则相当复杂,基本上这意味着函数以某种方式使用。在你的第二个例子中,这个函数没有被使用,所以没有必要。

有一个特别警告:一个virtual功能(除非它是纯)为总是视为ODR使用。

2

因为C++标准要求它被实现。来自C++ 03§10。3/8:

在类中声明的虚拟函数应该在该类中定义或声明为纯(10.4),或者两者兼有;但不需要诊断(3.2)。

所以你需要声明它是纯的(在右括号后面加上= 0后缀)或者定义它的实现。

至于为什么你的时候,你不叫在非虚拟案例的功能,是指C++ 03§3.2/ 2-3(重点煤矿)没有得到一个错误

2)的表达式潜在评价除非它出现在需要 (见5.19)整数表达式中,是操作者sizeof(5.3.3)的操作数,或是操作者typeid和 所述的操作数表达式不指定多态类类型的左值(5.2.8)。如果其名称出现在可能评估的表达式中,则使用对象或非重载功能虚拟成员函数是 ,如果它不是纯粹的。 [...]

3)每个程序应包含,其设置在 程序中使用每个非内联函数或对象中的正好一个定义;不需要诊断。定义可以在程序中显式出现,它可以在 标准或用户定义的库中找到,或者(在适当时)隐式定义(见12.1,12.4和12.8)。 内联函数应在使用它的每个翻译单元中定义。

因此,在非虚拟情况下,如果没有使用它,则不需要定义。但是在非纯虚拟情况下,即使它没有在代码中明确引用,它仍然被认为是由标准使用的,所以它的定义是必需的。请参阅A virtual member function is used if it is not pure?

相关问题