【发布时间】:2014-02-24 12:56:55
【问题描述】:
在 C++ 中,通常会看到以下内容:
C类头
//== C.h ==//
#pragma once
#include "B.h"
class C
{
B b;
};
B 类的标题
//== B.h ==//
#pragma once
#include "A.h"
class B
{
A a;
};
A类的头文件
//== A.h ==//
#pragma once
class A
{
};
因为C.h包含B.h,而B.h包含A.h; C.h 最终了解了有关 A.h 的实现细节。在这种情况下,标题仅包含三层深度,但在大型项目中,包含一个标题会很快导致包含数百个额外的标题。也会导致编译时间过长。
在 C++ 11 中,我可以将标题声明如下:
C类的头文件:
//== C.h ==//
#pragma once
#include <memory>
// proto
class B;
class C
{
std::unique_ptr<B> b;
};
B 类的标题
//== B.h ==//
#pragma once
#include <memory>
// proto
class A;
class B
{
std::unique_ptr<A> a;
};
A类的头文件
//== A.h ==//
#pragma once
class A
{
};
当用智能指针替换所有成员(类、结构)时,我可以包含C.h,而不必知道类 B 的实现。现在每个 cpp 文件只需要知道它的成员,而不必知道它的成员的内存布局。
我的问题是:
- 用唯一的指针替换所有类成员(无论是类还是结构)是一种好的设计实践(一个好主意)吗?他们的其他优点或缺点是什么?
【问题讨论】:
-
这类似于 pimpl 成语。不利的一面是,现在每次您想要访问成员时都会进行间接处理,并且您的类布局现在有效地分散在内存中。
-
不完全。 pImpl 将一个类拆分为私有和公共部分,并允许通过公共接口访问私有实现。它也是一个编译防火墙,但有些不同。
-
这甚至不是一个格式良好的代码。如果完整的类声明不存在,则不能使用默认删除器实例化 unique_ptr,因为它会在转发类型上调用 delete,这是未定义的行为。我同意@Simple,你提出的不过是Pimpl。
-
unique_ptr 将在包含相应标头的编译单元 (cpp) 内实例化。
-
@galop1n 你不需要完整的类型,否则不可能使用
unique_ptr实现pimpl。但是你需要一个析构函数声明。见this related question。
标签: c++ c++11 smart-pointers