我使用的是 PIMPL 成语,特别是我使用的是这篇文章提供的模板。鉴于下面的一组类并使用 VS2015 Update 3 进行编译,我得到了编译错误:
错误 C2027 使用未定义类型“C::C_impl”(编译源文件 src\A.cpp)
错误 C2338 无法删除不完整的类型(编译源文件 src\A.cpp)
警告 C4150 删除指向不完整类型“C::C_impl”的指针;没有调用析构函数(编译源文件 src\A.cpp)
我可以通过取消注释来解决这个问题C::~C()
,这让我相信某些东西正在阻止~C()
自动生成,但我不明白是什么。根据此参考,如果以下任何一项为真,则类型 T 的析构函数被隐式定义为已删除:
- T 有一个不能被破坏的非静态数据成员(已删除或不可访问的析构函数)
- T 具有无法破坏的直接或虚拟基类(已删除或不可访问的析构函数)
- T 是一个联合,并且有一个带有非平凡析构函数的变体成员。
- 隐式声明的析构函数是虚拟的(因为基类有一个虚拟析构函数),并且查找释放函数(运算符 delete() 会导致调用模棱两可、已删除或不可访问的函数。
第 2、3 和 4 项显然不适用于C
,而且我不认为第 1 项适用,因为pimpl<>
(C
的唯一成员) 明确定义了析构函数。
有人可以解释发生了什么吗?
啊
#pragma once
#include <Pimpl.h>
class A
{
private:
struct A_impl;
pimpl<A_impl> m_pimpl;
};
溴化氢
#pragma once
#include "C.h"
class B
{
private:
C m_C;
};
通道
#pragma once
#include <Pimpl.h>
class C
{
public:
// Needed for the PIMPL pattern
//~C();
private:
struct C_impl;
pimpl<C_impl> m_pimpl;
};
A.cpp
#include <memory>
#include "A.h"
#include "B.h"
#include <PimplImpl.h>
struct A::A_impl
{
std::unique_ptr<B> m_pB;
};
// Ensure all the code for the template is compiled
template class pimpl<A::A_impl>;
C.cpp
#include <C.h>
#include <PimplImpl.h>
struct C::C_impl { };
// Needed for the PIMPL pattern
//C::~C() = default;
// Ensure all the code for the template is compiled
template class pimpl<C::C_impl>;
为了完整起见,上面引用的帖子中的 PIMPL 实现:
粉刺.h
#pragma once
#include <memory>
template<typename T>
class pimpl
{
private:
std::unique_ptr<T> m;
public:
pimpl();
template<typename ...Args> pimpl(Args&& ...);
~pimpl();
T* operator->();
T& operator*();
};
PimplImpl.h
#pragma once
#include <utility>
template<typename T>
pimpl<T>::pimpl() : m{ new T{} } {}
template<typename T>
template<typename ...Args>
pimpl<T>::pimpl(Args&& ...args)
: m{ new T{ std::forward<Args>(args)... } }
{
}
template<typename T>
pimpl<T>::~pimpl() {}
template<typename T>
T* pimpl<T>::operator->() { return m.get(); }
template<typename T>
T& pimpl<T>::operator*() { return *m.get(); }
关于上面代码的几点说明:
- 我正在尝试向我的图书馆的消费者公开
A
和C
保持B
内部信息。 - 这里没有B.cpp,它会是空的。