Как я могу использовать один и тот же деструктор impl в классе, производном от базового класса PIMPL? - PullRequest
0 голосов
/ 20 ноября 2018

Я пытаюсь создать класс, который наследует от базового класса, который использует идиому PIMPL.

У меня есть базовый класс base.h:

#include <memory>

class Base {
 public:
  class Impl;
  Base(std::unique_ptr<Base::Impl> impl);
  virtual ~Base();

 private:
  std::unique_ptr<Base::Impl> impl_;
};

, который реализованв base.cpp:

#include "base.h"

class Base::Impl {
 public:
  Impl() {}
  ~Impl() {}
};

Base::Base(std::unique_ptr<Base::Impl> impl) : impl_(std::move(impl)) {}
Base::~Base() {}

, который затем выводится в derived.cpp:

#include "base.h"

class Derived : public Base {
 public:
  Derived() : Base(nullptr) {}
  ~Derived() override {}
};

Когда я компилирую эти три файла, я получаю следующую ошибку:

In file included from /usr/include/c++/7/memory:80:0,
                 from base.h:1,
                 from derived.cpp:1:
/usr/include/c++/7/bits/unique_ptr.h: In instantiation of ‘void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = Base::Impl]’:
/usr/include/c++/7/bits/unique_ptr.h:268:17:   required from ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = Base::Impl; _Dp = std::default_delete<Base::Impl>]’
derived.cpp:5:27:   required from here
/usr/include/c++/7/bits/unique_ptr.h:76:22: error: invalid application of ‘sizeof’ to incomplete type ‘Base::Impl’
  static_assert(sizeof(_Tp)>0,

, какой имеет смысл, поскольку ~Impl() для производного класса не существует.После того, как я добавлю следующий фрагмент к derived.cpp перед определением класса Derived:

class Base::Impl {
 public:
  Impl() {}
  ~Impl() {}
};

, он хорошо скомпилируется.Есть ли способ для derived.cpp использовать деструктор Impl из base.cpp, не добавляя его в какой-либо другой общий файл, который используют base.cpp и derived.cpp?Я также заметил, что эта проблема возникает только из-за того, что конструктор принимает значения от unique_ptr до Base::Impl.Если я заменю этот конструктор пустым конструктором, который просто присваивает new Impl Base::impl_, мне не нужно включать деструктор, как это было выше.Что отличается в этой ситуации?

...