C++;链接时未定义虚拟函数-为什么? 我在C++中使用虚函数有点麻烦,我可能在构造函数中滥用它们。问题是,当将组件库(由我编写)链接到最终可执行文件时,虚拟函数被标记为未定义,即使我已经为它编写了一个实现并链接了它

C++;链接时未定义虚拟函数-为什么? 我在C++中使用虚函数有点麻烦,我可能在构造函数中滥用它们。问题是,当将组件库(由我编写)链接到最终可执行文件时,虚拟函数被标记为未定义,即使我已经为它编写了一个实现并链接了它,c++,inheritance,undefined,virtual-functions,C++,Inheritance,Undefined,Virtual Functions,我有以下课程: template<class BufferType, class ConnectionType, class HandlerType> class UdpConnection { public: UdpConnection(size_t dispatchCount) : service(), listener(service), pool(dispatchCount), sysMsgHandlers(), bufferP

我有以下课程:

template<class BufferType, class ConnectionType, class HandlerType>
class UdpConnection
{
public:
UdpConnection(size_t dispatchCount) : service(),
        listener(service),
        pool(dispatchCount), sysMsgHandlers(),
        bufferPool(), buffers()
    {
        assert(dispatchCount > 0);
        initBuffers(dispatchCount);
        initSysHandlers();
    }
protected:
    virtual void initSysHandlers() = 0;
}
如您所见,我正在调用构造函数中的虚拟函数。就我所知,这应该没问题,因为我知道我的子类构造函数不会被调用,所以我不能使用任何实例变量,但我只是简单地向std::map添加一些特定于子类的项

Linking CXX static library libnetwork.a
[ 75%] Built target network                                                                                           
Scanning dependencies of target testclient
[ 87%] Building CXX object CMakeFiles/testclient.dir/src/test/testclient.cpp.o                                        
Linking CXX executable testclient                                                                                     
src/network/libnetwork.a(udpclient.cpp.o): In function `voip::network::UdpConnection<voip::network::client::SyncBufferHandler, voip::network::client::UdpClient, voip::network::client::ClientNetworkHandler>::UdpConnection(unsigned long)':
udpclient.cpp:(.text._ZN4voip7network13UdpConnectionINS0_6client17SyncBufferHandlerENS2_9UdpClientENS2_20ClientNetworkHandlerEEC2Em[voip::network::UdpConnection<voip::network::client::SyncBufferHandler, voip::network::client::UdpClient, voip::network::client::ClientNetworkHandler>::UdpConnection(unsigned long)]+0x10d): undefined reference to `voip::network::UdpConnection<voip::network::client::SyncBufferHandler, voip::network::client::UdpClient, voip::network::client::ClientNetworkHandler>::initSysHandlers()'
collect2: ld returned 1 exit status
链接CXX静态库libnetwork.a
[75%]建立目标网络
扫描目标testclient的依赖项
[87%]构建CXX对象cmakfiles/testclient.dir/src/test/testclient.cpp.o
链接CXX可执行testclient
src/network/libnetwork.a(udpclient.cpp.o):在函数“voip::network::UdpConnection::UdpConnection(unsigned long)”中:
udpclient.cpp:(.text._ZN4voip7network13UdpConnectionINS0_6client17SyncBufferHandlerENS2_9UdpClientENS2_20ClientNetworkHandlerEEC2Em[voip::network::UdpConnection::UdpConnection(unsigned long)]+0x10d):对“voip::network::UdpConnection::initSysHandlers()”的未定义引用
collect2:ld返回了1个退出状态

我做错了什么?请询问您是否需要更多信息,希望尽可能简短

不要在构造时调用虚拟函数。构造从基类转到派生类。因此构造函数
UdpConnection::UdpConnection
还不知道该类已被继承。此时尚未形成派生类的vtable,并且要调用的重载函数的地址未知。

您不应该在构造函数或析构函数中调用虚拟函数,因为它们没有预期的行为。在构造函数返回之前,对象尚未完全创建


在派生类构造函数之前调用基类构造函数;因此,首先创建并定义基类数据成员和函数。因此,在您的情况下,UdpConnection构造函数将尝试调用UdpConnection::initSysHandlers,而不是UdpClient::initSysHandlers,因为它尚未创建。由于UdpConnection::initSysHandlers是纯虚拟的,因此在这一点上它是未定义的。

您正在从基类构造函数调用虚拟函数。在构建和销毁期间,虚拟功能的调度有特殊规则:

实际上,当基类
UdpConnection
的构造函数正在执行时,对象的动态类型是
UdpConnection
,而不是
UdpClient
,因此选择的虚拟函数的最终重写器是
UdpConnection
的重写器,而不是最派生的类
UdpClient

这意味着,当您在
UdpConnection
构造函数中调用
initSysHandlers()
时,总是
UdpConnection::initSysHandlers()
被调用,而不是最派生类中的重写。由于尚未提供
UdpConnection::initSysHandlers()
的定义,因此会出现链接器错误


专家建议您应该这样做。

呼叫是否具有预期行为取决于您预期的行为。即使该行为碰巧看起来是预期的,它仍然是错误的。这实际上比“vtable尚未形成”要复杂得多有。我仍然非常确定这个问题与vtable有关。当对象文件在统一的地址空间中组合在一起时,链接过程中会出现问题。希望有一天能多了解C++内部的东西。好的,谢谢!我以为是这样的,但是错误消息太不描述性了(因为我只是认为我不能使用子类的任何成员)。有时我希望编译器能添加更多的描述性提示@麦克斯:是的,如果你从构造函数调用一个虚拟函数,一些编译器会很有帮助地警告你。其他编译器没有那么有用。我错误地单击了向下箭头,现在它被修复了。。我终于赢得了我的评论家徽章xD@ak:噢;哈没问题。:-)谢谢你的提醒。
void UdpClient::initSysHandlers()
{

}
Linking CXX static library libnetwork.a
[ 75%] Built target network                                                                                           
Scanning dependencies of target testclient
[ 87%] Building CXX object CMakeFiles/testclient.dir/src/test/testclient.cpp.o                                        
Linking CXX executable testclient                                                                                     
src/network/libnetwork.a(udpclient.cpp.o): In function `voip::network::UdpConnection<voip::network::client::SyncBufferHandler, voip::network::client::UdpClient, voip::network::client::ClientNetworkHandler>::UdpConnection(unsigned long)':
udpclient.cpp:(.text._ZN4voip7network13UdpConnectionINS0_6client17SyncBufferHandlerENS2_9UdpClientENS2_20ClientNetworkHandlerEEC2Em[voip::network::UdpConnection<voip::network::client::SyncBufferHandler, voip::network::client::UdpClient, voip::network::client::ClientNetworkHandler>::UdpConnection(unsigned long)]+0x10d): undefined reference to `voip::network::UdpConnection<voip::network::client::SyncBufferHandler, voip::network::client::UdpClient, voip::network::client::ClientNetworkHandler>::initSysHandlers()'
collect2: ld returned 1 exit status