Я пытаюсь создать класс, который наследует от базового класса, который использует идиому 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_
, мне не нужно включать деструктор, как это было выше.Что отличается в этой ситуации?