我有一个声明如下的类:
class TestFoo {
public:
TestFoo();
virtual void virtualFunction();
void nonVirtualFunction();
};
我尝试以这种方式实现
TestFoo::TestFoo(){}
void TestFoo::nonVirtualFunction(){}
在编译时返回错误:
undefined reference to vtable for TestFoo
我试过了:
TestFoo::TestFoo(){}
void TestFoo::nonVirtualFunction(){}
void TestFoo::virtualFunction(){}
编译确定与这些帖子的答案一致:
令我困惑的是,我认为声明虚函数的重点在于我不需要定义它。在这个例子中,我不打算创建任何TestFoo实例,而是创建从TestFoo继承的(具体)类的实例。但是,我仍然想为TestFoo的每个子类定义函数nonVirtualFunction。
我做错了什么?
谢谢!
答案 0 :(得分:7)
声明虚函数的重点是我不会 需要定义它
不完全,它说“我可能想用派生类中的其他东西替换此函数的实现。”
我可能误解了你的问题,但你似乎暗示你不认为你可以在C ++中定义纯虚拟成员函数,你可以。您可以声明,如下所示。
virtual void virtualFunction() = 0;
通常,纯虚函数不会定义,但当然可以。这说“这个函数没有默认实现,因为它并不总是有意义,但我会为你提供一个你可以选择的实现。”
顺便说一下,如果一个类有任何虚拟函数,你还应该定义一个虚拟析构函数,因为它是完全合法的(并且经常被推荐)指向派生类的基类(智能)指针 - 没有虚拟析构函数,该对象可能无法正确delete
。
答案 1 :(得分:3)
......我想到了宣告一个问题的重点 虚函数是我不需要定义它...
对于该设施,您有一个名为纯虚拟方法的功能:
virtual void virtualFunction() = 0; // no linking error now
请注意,virtual
方法无法保持未实现状态。原因是对于virtual
主体内的每个class
方法声明,必须有一个vtable
条目。未能找到其正文会导致链接错误。
此限制的目的:
除非一个类是抽象的 - 也就是说它至少有一个虚函数 - 否则你无法向编译器保证你不会声明TestFoo
的对象。当您执行以下操作时会发生什么:
DerivedOfTestFoo obj1;
TestFoo obj2 = obj1, *p = &obj2; // object slicing
p->virtualFunction(); // where is the body?
其他情况;在构造函数中没有virtual
机制:
TestFoo::TestFoo () {
this->virtualFunction(); // where is the body?
}
我们可以得出结论,编译器遵循“更安全而不是抱歉”的规则。 :)
答案 2 :(得分:1)
您的描述与抽象类的情况完全匹配。将您的虚函数声明为:
virtual void VirtualFunction () = 0;
这意味着您没有在此类中实现该功能。结果,班级变得抽象。也就是说,不能实例化此类的裸对象。
此外,您应该提供虚拟析构函数。
更新:一些澄清......
该语言允许您重新定义非虚拟功能。但是,在某些情况下可能会调用错误的版本:
derived D; // rB is a reference to base class but it
base & rB=D; // points to an object of the derived class
rB.NonVirtualFunction (); // The base-class version is called
出于这个原因,现在强烈建议不要重新定义非虚函数。请参阅Scott Meyers的“Effective C ++,第三版:55改进程序和设计的具体方法”,第36项:“永远不要重新定义继承的非虚函数。”
另见第7项:“在多态基类中声明析构函数虚拟”。一个例子:
base * pB = new derived;
delete pB; // If base's destructor is not virtual,
// ~derived() will not be called.
如果您想知道为什么默认情况下并非所有内容都是虚拟的,原因是调用虚函数比调用非虚函数稍慢。哦,具有虚函数的类的对象每个占用几个字节。
答案 3 :(得分:0)
如果你想把这个虚函数作为纯虚函数,那么不要定义它,virtual void virtualFunction()= 0;