在C ++中考虑以下三个程序:
struct base{
virtual ~base() =0;
};
struct derived: public base{
~derived();
};
derived::~derived(){}
int main(){}
struct base{
virtual ~base() =0;
};
struct derived: public base{
~derived(){}
};
int main(){}
struct base{
virtual void func() =0;
};
struct derived: public base{
void func();
};
void derived::func(){}
int main(){}
程序#2和#3编译并运行正常但是第一个出现以下错误:
Undefined symbols for architecture x86_64: "base::~base()", referenced from: derived::~derived() in main-d923b9.o ls: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation)
我想知道为什么我无法在类定义之外定义虚拟析构函数,但是我能够在类定义中完成它。另外,我可以在类外部定义方法,而不是析构函数。
答案 0 :(得分:4)
这是错误的
struct base{
virtual ~base() =0;
};
因为未定义base::~base
。尽管它已被声明为纯虚拟,但它需要被定义(在类之外,没有语法方法将函数声明为纯虚拟并将其定义为内联),因此derived
可以继承它:
struct base
{
virtual ~base() = 0;
};
base::~base() {}
我想知道为什么我无法在类定义之外定义虚拟析构函数
嗯,你可以:我刚刚做了。
那么,为什么需要实现一个已被声明为纯虚函数的函数(~base
)?
由于derived
继承自base
,当类型derived
的对象被破坏时,它必然会调用base
的析构函数。这是继承的工作方式。从某种意义上说,derived::~derived
需要与base::~base
相关联。即使base::~base
是纯虚拟的(意味着继承自base
的类不是完整类型,除非它定义了析构函数),它需要来定义{{1}找到它并且链接器变得快乐。
答案 1 :(得分:1)
为什么程序2构建的答案在于链接如何工作。当函数定义在类声明之外时,链接器需要在最终的二进制文件中创建函数体,因此它也需要具有~base()定义。
如果在主体中放入案例2 derived d;
,则会得到与案例1相同的错误,因为链接器必须创建派生成员函数定义,并且需要~base()body作为在案例1中。