虚析构函数和链接器错误
C++ - virtual destructors and linker errors
我得到了我写的这个界面:
#ifndef _I_LOG_H
#define _I_LOG_H
class ILog {
public:
ILog();
virtual ~ILog();
virtual void LogInfo(const char* msg, ...) = 0;
virtual void LogDebug(const char* msg, ...) = 0;
virtual void LogWarn(const char* msg, ...) = 0;
virtual void LogError(const char* msg, ...) = 0;
private:
Monkey* monkey;
};
#endif
方法是纯虚的,因此必须通过派生类来实现。如果我尝试创建一个继承此接口的类,我会得到以下链接器错误:
Undefined reference to ILog::ILog
Undefined reference to ILog::~ILog
我明白为什么有一个虚拟析构函数(以确保派生的析构函数被调用),但我不明白为什么我得到这个链接器错误。
编辑:好的,所以我也需要定义虚析构函数。但是我仍然可以在虚析构函数的定义中执行一些操作吗?或者它会简单地调用派生类的析构函数并跳过它吗?比如,这会触发:
virtual ~ILog() { delete monkey; }
您没有定义构造函数和析构函数,您只是声明了它们
试
class ILog {
public:
//note, I want the compiler-generated default constructor, so I don't write one
virtual ~ILog(){} //empty body
virtual void LogInfo(const char* msg, ...) = 0;
virtual void LogDebug(const char* msg, ...) = 0;
virtual void LogWarn(const char* msg, ...) = 0;
virtual void LogError(const char* msg, ...) = 0;
};
- Constructor:一旦你声明了一个构造函数,任何构造函数,编译器都不会为你生成默认的构造函数。派生类的构造函数尝试调用接口的构造函数,它没有定义,只是声明。要么提供定义,要么删除 声明
- Destructor:其他注意事项(例如,与上面类似的注意事项)您的析构函数是虚拟的。每个非纯虚函数必须有一个定义(因为根据定义使用)。
仍然可以执行虚析构函数定义中的内容吗?还是简单地调用派生类的析构函数并跳过它?比如,这会触发
吗?
是的,你可以。当调用派生类的析构函数时,它将自动调用基类的析构函数。然而,我认为在接口的析构函数中做这样的事情没有什么意义。但从技术上讲,你可以在析构函数中做任何事情,即使它是虚的
您忘记为虚析构函数添加一个空函数。函数体实际上不做任何事情,c++可能会将低级析构代码放在派生类析构函数中(对此不完全确定),但它仍然是必需的:
#ifndef _I_LOG_H
#define _I_LOG_H
struct ILog {
virtual ~ILog();
// virtual ~ILog() = 0; // either works
virtual void LogInfo(const char* msg, ...) = 0;
virtual void LogDebug(const char* msg, ...) = 0;
virtual void LogWarn(const char* msg, ...) = 0;
virtual void LogError(const char* msg, ...) = 0;
};
#endif
CPP文件:
ILog::~ILog()
{ // this does get called
}
更新的例子:
#include <iostream>
struct Monkey
{
int data;
};
struct ILog
{
ILog() : monkey(0) {}
virtual ~ILog() = 0;
virtual void LogInfo(const char* msg, ...) = 0;
virtual void LogDebug(const char* msg, ...) = 0;
virtual void LogWarn(const char* msg, ...) = 0;
virtual void LogError(const char* msg, ...) = 0;
void storeMonkey(Monkey* pM)
{
delete monkey;
monkey = pM;
}
void message()
{
std::cout << "monkey->data contains " << monkey->data;
}
private:
Monkey* monkey;
};
struct ILogD : ILog
{
int data;
ILogD(Monkey* pM)
{
storeMonkey(pM);
}
void LogInfo(const char* msg, ...) {};
void LogDebug(const char* msg, ...) {};
void LogWarn(const char* msg, ...) {};
void LogError(const char* msg, ...) {};
};
ILog::~ILog()
{
delete monkey;
}
int main()
{
ILogD o(new Monkey());
o.message();
}
只要提供构造函数和析构函数的内联版本,编译器就不会生成对它们的引用,从而导致链接器失败。
ILog() {};
virtual ~ILog() {};
并非全输了!调用纯虚析构函数,模板类除外。c++没有真正的接口,但纯抽象类的工作方式相同,所有虚函数都设置为0,创建一个空虚函数表。大多数c++程序员避免纯抽象类以外的任何东西的多重继承,因为不同的编译器在实现上存在复杂性和差异。你的类不是一个纯虚类,因为你有成员数据,你需要一个非纯虚函数的析构函数来清理它。不要害怕有变通的办法!
你的结构类需要看起来像这样:
#ifndef _I_LOG_H
#define _I_LOG_H
struct ILog {
virtual ~ILog() = 0; // JDM: This is how you make it abstract
virtual void LogInfo(const char* msg, ...) = 0;
virtual void LogDebug(const char* msg, ...) = 0;
virtual void LogWarn(const char* msg, ...) = 0;
virtual void LogError(const char* msg, ...) = 0;
};
#endif
正确的方法是在你的ILog.cpp:
#include "Ilog.h"
// only for the dtor
ILog::~ILog(){
// code here will get called!
}
我确实提到了一些关于模板的事情,这超出了你的问题的范围,但理解它很重要。必须为模板类实现专门的纯虚析构函数:
#ifndef _I_LOG_H
#define _I_LOG_H
template<class T> class ILog {
virtual ~ILog() = 0; // JDM: This is how you make it abstract
virtual void LogInfo(T msg, ...) = 0;
virtual void LogDebug(T msg, ...) = 0;
virtual void LogWarn(T msg, ...) = 0;
virtual void LogError(T msg, ...) = 0;
};
#endif
假设我有:
class LogMsg {
const char* message;
LogMsg(const char * const msg) {
message = msg;
}
// More Stuff
}
然后我像这样使用LogMsg:
#include "ILog.h"
class Log : ILog<LogMsg> {
// implement ILog...
virtual ~Log();
}
和在我的CPP:
#include "Log.h"
Log::~Log() {
// this gets called
}
// Link error without the following
template<class LogMsg> ILog<LogMsg>::~ILog {
// This gets called.
}
- Netbeans 10:错误:链接器命令失败,退出代码为 1(使用 -v 查看调用)
- CMake 错误:链接器命令失败,退出代码为 1 和 cpp.o 文件
- clang:错误:链接器命令失败,退出代码为 1(使用 -v 查看调用) - 体系结构的未定义符号 x86_64:
- 如何修复 clang: 错误:链接器命令失败,退出代码为 1(使用 -v 查看调用)
- Android NDK.Build命令失败.未定义的引用.clang++:错误:链接器命令失败,退出代码为1
- 使用cmake错误链接boost日志
- 错误:链接器命令失败,退出代码为 1(使用 -v 查看调用):在 Macbook 上
- C++ XCODE ld:找不到体系结构x86_64 clang 的符号:错误:链接器命令失败,退出代码为 1(使用 -
- clang:错误:链接器命令失败,C++代码中的退出代码为 1(使用 -v 查看调用)
- 静态库中的 g++ 错误链接函数
- 未定义的参考错误链接天然函数Android
- C++编译错误:ld:找不到体系结构x86_64 clang 的符号:错误:链接器命令失败,退出代码为 1(使用 -v
- QT Q_PROPERTY错误:链接器命令失败,退出代码为 1(使用 -v 查看调用)
- ld:找不到体系结构x86_64 clang 的符号:错误:链接器命令失败,退出代码为 1(使用 -v 查看调用)
- OSX MOJAVE -LD:架构X86_64 clang找不到符号:错误:链接器命令失败,出口代码1
- C 错误链接器命令失败了出口代码1(使用-V查看调用)
- LD:架构x86_64 clang找不到符号:错误:链接器命令失败,出口代码1(使用-v to See
- 聚输出错误 - 链接列表
- Xcode链接器错误:链接器命令失败,退出代码为1(使用-v查看调用)
- 尝试构建C DLIB示例无法与数百个未定义的参考错误链接