为什么必须定义未使用的虚函数



我发现非常奇怪的是,未使用的虚函数仍然必须与未使用的普通函数不同。我对创建类对象时创建的隐式虚表虚指针有一些了解-这在一定程度上回答了问题(必须定义函数以便可以定义指向虚函数的指针),但这将我的查询进一步推回。

如果虚函数完全没有机会被调用,为什么要为函数创建虚表项呢?
class A{
    virtual bool test() const;
};
int main(){
    A a; //error: undefined reference to 'vtable for A'
}

尽管我声明了A::test(),但它从未在程序中使用过,但它仍然抛出了一个错误。编译器可以不运行整个程序并意识到test()从未被调用-因此不需要虚函数表条目吗?或者对编译器的期望是不合理的?

因为这将不可避免地成为编译器编写者解决的一个非常困难的问题,当能够使虚函数未定义的有用性充其量是可疑的。编译器作者肯定有更好的问题要解决。

此外,你正在使用那个函数,即使你没有调用它。你正在取它的地址

OP说他已经知道虚表和虚指针,所以他理解未使用的虚函数和未使用的非虚函数之间的区别:未使用的非虚函数不会在任何地方被引用,而虚函数至少在其类的虚表中被引用一次。所以,本质上的问题是,如果虚函数不在任何地方使用,为什么编译器没有足够聪明地避免在虚函数表中放置对虚函数的引用。这将允许函数变为undefined

编译器通常一次只能看到一个。cpp文件,所以它不知道你是否在某个地方有调用该函数的源文件。

一些工具支持这种分析,他们称之为"全局"分析或类似的东西。您甚至可能发现它内置在某些编译器中,并且可以通过某些编译器选项访问。但是它在默认情况下是不启用的,因为它会极大地减慢编译速度。

事实上,让非虚函数未定义的原因也与缺乏全局分析有关,但方式不同:如果编译器知道您省略了函数的定义,它可能至少会警告您。但由于它不做全局分析,它不能。如果你确实尝试使用一个未定义的函数,编译器不会捕捉到这个错误:它会被链接器捕捉到。

所以,只要定义一个包含ASSERT(FALSE)的空虚函数,然后继续你的生活。

虚函数的全部意义在于可以通过基类指针调用它们。如果您从不使用基类虚函数,那么为什么要定义它呢?如果使用了它,那么您要么必须离开父实现(如果它不是纯虚的),要么定义您自己的实现,以便通过基类使用您的对象的代码可以实际使用它。在这种情况下,函数使用,只是没有直接使用。

最新更新