我是C ++ 11的新手,我正在尝试构建一个经典的接口/实现对。请考虑以下示例:
#include <iostream>
#include <memory>
// Interface
class IFace {
public:
virtual ~IFace () = 0;
};
// Why must I define this concrete implementation?
inline IFace::~IFace () { }
// Implementation
class Impl : public IFace {
public:
virtual ~Impl () { }
};
int main (int argc, char ** argv) {
auto impl = std::shared_ptr<Impl> (new Impl ());
return 0;
}
如果我在界面inline IFace::~IFace () { }
上注释掉了不合需要的具体析构函数,我会收到链接错误
Undefined symbols for architecture x86_64:
"IFace::~IFace()", referenced from:
Impl::~Impl() in ifac_impl.cpp.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
即使界面和实现是模板化的,我也必须这样做:
// Template IFace2
template <typename T>
class IFace2 {
public:
virtual ~IFace2 () = 0;
};
// I have to do this even if the pair is templated.
template <typename T>
inline IFace2<T>::~IFace2<T> () { }
template <typename T>
class Impl2 : public IFace2<T> {
public:
virtual ~Impl2 () { }
};
int main (int argc, char ** argv) {
auto impl = std::shared_ptr<Impl> (new Impl ());
auto impl2 = std::shared_ptr<Impl2<double> > (new Impl2<double> ());
return 0;
}
为什么呢?
第二个问题是&#34;我是否以错误的方式解决这个问题?&#34;也就是说,对于我想做的事情,是否有更好的模式(成语?)?我承认我试图将我用C#开发的概念模式融入C ++ 11。这样理智吗?如果没有,那么理智的方式是什么?
答案 0 :(得分:6)
析构函数不应该是纯虚拟的。这将使类抽象,因此无法实例化。只需将其定义为default
:
class IFace {
public:
virtual ~IFace () = default;
};
答案 1 :(得分:6)
当您在派生类中重写虚函数,然后调用它时,除非您明确调用它,否则不会调用基本实现。
例如,
struct base
{
virtual void foo() {}
};
struct derived : base
{
void foo() override {}
};
base *b = new derived;
b->foo(); // this will not call base::foo
同样适用于纯虚函数。
但是,对于(纯)虚拟析构函数,基础析构函数将被调用(因为需要销毁基础子对象)。因此,如果您有纯虚拟析构函数,那么必须提供实现。否则,您将永远无法实例化任何派生类。