为什么我必须在抽象类上实现具体的析构函数?

时间:2014-06-15 22:39:06

标签: c++ c++11 interface

我是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。这样理智吗?如果没有,那么理智的方式是什么?

2 个答案:

答案 0 :(得分:6)

析构函数不应该是纯虚拟的。这将使类抽象,因此无法实例化。只需将其定义为default

class IFace {
public:
    virtual ~IFace () = default;
};

Live demo

答案 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

同样适用于纯虚函数。

但是,对于(纯)虚拟析构函数,基础析构函数将被调用(因为需要销毁基础子对象)。因此,如果您有纯虚拟析构函数,那么必须提供实现。否则,您将永远无法实例化任何派生类。