首先,这个weak-vtables的完整警告信息大概长这样:
warning: ‘XXX’ has no out-of-line virtual method definitions; its vtable
will be emitted in every translation unit [-Wweak-vtables]
而这个警告信息的来源一般是这样:
// XXX.h中
class BaseData
{
public:
virtual ~BaseData() = default;
int _base_data = 0;
};
class DerivedDataA final : public BaseData
{
public:
int _derived_data_a = 0;
};
class DerivedDataB final : public BaseData
{
public:
int _derived_data_b = 0;
};
在这个头文件中,声明了一个基类BaseData和两个派生类DerivedDataA和DerivedDataB。这几个类原本是要描述这样的应用场景:定义有两种具有某些共性的数据类A和B。其实,如果只是这种程度的需求的话,完全可以不碰多态这个特性的,也就是可以去掉BaseData中的虚析构函数,这样完全就是描述一个简单的具有一个共同int型成员变量_base_data,且各自有专用int型成员变量的两个类。然而,这个应用场景后来用偏偏需要在一个通用容器,比如vector中,保存这两个派生类的实例,这时就必须用到多态了,也就是要把基类的析构设为virtual!此时即可以用一个std::vector<BaseData *>的容器来保存两种派生类的实例了,使用时配合RTTI或dynamic_cast便可做出类型区分。而这时,当你再不同的cpp中include这个.h的时候,标题中的问题就来了,clang扫描会提示你:
warning: ‘BaseData’ has no out-of-line virtual method definitions; its vtable
will be emitted in every translation unit [-Wweak-vtables]
当然,我只写了一个类的警告,而实际上这三个类都会收到同样的警告!虽然,这个警告并不会对程序最终的运行结果造成任何影响,但是,这种写法会导致这三个类的虚函数表(vtable,具体说明可自行百度)在每个include这个头文件的cpp文件中生成一份,也就是在cpp编译后的.o中存在一份,而最后link的时候再排重去除(这里我只是简单说明了下,完整原因解释要更复杂些,可自行研究),显然这样会影响link速度,那么如何回避这个情况呢?简单来说就是随便找个cpp中给这三个类的任意虚函数写个实现,比如析构函数,但是这样写一个空析构实现的话呢,又会导致这个class变为non-trivial类(自行百度),如果你的这些类确实需要有一些释放操作在析构函数中进行的话倒是无关紧要,而对于我写的这个例子,并不需要什么特别的释放操作,因此,还是不要影响编译器默认生成的构造、拷贝构造等函数比较好,最终加了一个无关紧要的虚函数:
// XXX.h中
class BaseData
{
public:
virtual ~BaseData() = default;
virtual std::string getType();
int _base_data = 0;
};
class DerivedDataA final : public BaseData
{
public:
std::string getType() override;
int _derived_data_a = 0;
};
class DerivedDataB final : public BaseData
{
public:
std::string getType() override;
int _derived_data_b = 0;
};
// 某个.cpp中
#include "XXX.h"
std::string BaseData::getType()
{
return "base";
}
std::string DerivedDataA::getType()
{
return "derived_a";
}
std::string DerivedDataB::getType()
{
return "derived_b";
}
这样,就可以消除这个警告且减轻下link的负担了。
博主友情提示:
如您在评论中需要提及如QQ号、电子邮件地址或其他隐私敏感信息,欢迎使用>>博主专用加密工具v3<<处理后发布,原文只有博主可以看到。