【发布时间】:2014-01-27 04:17:41
【问题描述】:
Here 我问了一个问题,试图避免使用 window.h 文件中的内容污染我的代码库,以确保我的代码库是跨平台兼容的。有人向我展示了我提出的一般想法是指 pimpl 成语。今天我把这个成语向前或向后迈了一步,我不确定是哪一个。我相当确定我的实现在技术上不会引起问题,但有点难看。我的主要问题是:有人知道实施会导致问题的任何原因吗?还有什么方法可以让它不那么……嗯……丑,更容易维护?
文件 ElementsToHide.h 模拟我不想污染整个项目的全局命名空间的文件的内容,例如 windows.h。
文件 ClassWithPImpl.h 包含一个 PImpl 结构的定义,该结构仅包含一个 char[16],但仅在没有定义标志以指示其先前声明的情况下才定义该结构。 char[16] 只是为了在所有文件中保持结构的大小相同。
ClassWithPImpl.cpp 文件当然定义了类的功能,但与可能包含 ClassWithPImpl.h 的任何其他文件不同,ClassWithPImpl.cpp 定义了它自己的 PImpl 结构版本,它使用来自 ElementsToHide.h 的数据类型。这两个结构体的大小是一样的,也就是说ClassWithPImpl.cpp在编译的时候可以看到PImpl结构体的实际内容。每个其他文件只看到一个私有的 char 数组。这意味着没有其他文件包含 ElementsToHide.h,因此没有其他文件被它的数据类型、函数等污染...
main.cpp 是一个小程序,它打印出类和 PImpl 结构的大小以确保它们相同。商业应用程序可能会使用断言来确保结构保持相同的大小。
以下是应用程序中的所有文件: ElementsToHide.h
#ifndef ELEMENTS_TO_HIDE_H
#define ELEMENTS_TO_HIDE_H
typedef short int16;
typedef long int32;
typedef long long int64;
#endif
ClassWithPImpl.h
#ifndef CLASS_WITH_PIMPL_H
#define CLASS_WITH_PIMPL_H
#ifndef PIMPL_DEFINED
#define PIMPL_DEFINED
struct PImpl
{
char data[16];
};
#else
struct PImpl;
#endif
class ClassWithPImpl
{
private:
PImpl pImpl;
public:
ClassWithPImpl();
void print();
};
#endif
ClassWithPImpl.cpp
#include <iostream>
using namespace std;
#include "ElementsToHide.h"
#define PIMPL_DEFINED
struct PImpl
{
int16 shortInt;
int32 mediumInt;
int64 longInt;
};
#include "ClassWithPImpl.h"
ClassWithPImpl::ClassWithPImpl()
{
pImpl.shortInt = 4;
pImpl.mediumInt = 1;
pImpl.longInt = 2;
}
void ClassWithPImpl::print()
{
cout << pImpl.shortInt << endl;
cout << "Size of class as seen from class: " << sizeof(ClassWithPImpl) << endl;
cout << "Size of PImpl as seen from class: " << sizeof(PImpl) << endl;
}
main.cpp
#include <iostream>
using namespace std;
#include "ClassWithPImpl.h"
int main()
{
//int32 shortInt;
//Program won't compile with this line, because despite the ClassWithPImpl using the int32 type defined in ElementsToHide.h, these types are never
//actually included into main.cpp.
ClassWithPImpl().print();
cout << "Size of Class as seen from Main: " << sizeof(ClassWithPImpl) << endl;
cout << "Size of PImple as seen from Main: " << sizeof(PImpl) << endl;
cout << sizeof(short) << ", " << sizeof(long) << ", " << sizeof(long long) << endl;
}
应用程序的输出是:
4
Size of class as seen from class: 16
Size of PImpl as seen from class: 16
Size of Class as seen from Main: 16
Size of PImple as seen from Main: 16
2, 4, 8
如您所见,类文件可以很好地查看和处理内部变量,而应用程序的其余部分则真正忘记了应用程序具有除 char[16] 之外的任何内部变量。默认的复制构造函数/操作符应该只工作文件,因为它只会复制数组内容。不需要析构函数,因为类中没有托管资源。引用指向隐藏数据结构的指针也不会浪费 CPU 时间,从实现文件查看时,它实际上直接包含在类定义中。这是丑陋的。是否有人知道这不起作用或会使情况进一步复杂化的情况?有没有什么方法可以简化它,而不需要在任何时候你想从中获取数据时都必须管理和取消引用的指针?
【问题讨论】:
-
您可能想阅读 GotW#28 - The Fast Pimpl Idiom at gotw.ca/gotw/028.htm
-
读起来很有趣。仍然使用 Pimpl 习惯用法,但使用自定义分配器来加速 Pimpl 的分配/释放。老实说,我仍然认为我更喜欢他的尝试#3。无需任何额外的分配/解除分配。隐藏的类变量不需要经过额外的指针取消引用。使用它本身并不需要复制构造函数/运算符。我必须承认,我只是更喜欢#3。
标签: c++ pointers struct cross-platform pimpl-idiom