2010-05-11 33 views
4

我正在开发一个库,并希望为我的用户提供一个与隐藏在名称空间中的真实实现分开的公共接口。这样,我就可以只更改HiddenQueue类而不更改myQueue,它只会暴露给用户。隐藏使用名称空间的内部类实现

如果我将HiddenQueue的C++代码放入myQueue.cpp文件,编译器会抱怨说_innerQueue的类型不完整。我认为链接器能够解决这个问题。我在这里做错了什么?

// myQueue.h 
namespace inner{ 
    class HiddenQueue; 
}; 

class myQueue{ 

public: 
    myQueue(); 
); 

private: 

    inner::HiddenQueue _innerQueue; 

}; 

/////////////////////////// 

// myQueue.cpp 
namespace inner{ 
    class HiddenQueue{}; 
}; 

回答

6

编译器需要通过看它在定义的头文件就知道对象的确切的内存布局。

您的代码表示,类MyQueueInnerQueue类型的成员,这将是记忆中的一部分MyQueue对象的布局。因此,要推导出MyQueue的内存布局,需要知道InnerQueue的内存布局。它没有,因为你说“哦,它在别处被定义”。

你正在尝试做什么与“PIMPLidiom”/“编译器防火墙”技术密切相关。

为了解决这个问题,您必须包括HiddenQueue.h在你的头或声明_innerqueue作为指针:

class myQueue { 

public: 
    myQueue(); 

private: 

    inner::HiddenQueue* _pinnerQueue; 
}; 

使用指针是可能的,因为一个指针有一个已知的内存大小(取决于您的目标体系结构),因此编译器无需查看HiddenQueue的完整声明。

+0

+1 PIMPL。这里有一篇文章来自创造这个术语的人:http://www.gotw.ca/gotw/024.htm – 2010-05-11 14:41:41

+0

嗯,在底线PIMPL招致一些运行时速度成本,并为您提供便于维护和编译速度的收益。无可否认,在一般情况下运行时速度成本并不是问题(如果不是这样,你可能知道这很重要),但恕我直言,在代码库中不需要小于一定大小的PIMPL。 – Jon 2010-05-11 14:46:57

1

为了能够成为一个类的成员,你需要有一个定义它,而不仅仅是一个声明。 (一个声明足够用于指针或对类的引用)。

1

您需要提供指针_innetQueue而不是对象本身:

std::auto_ptr<inner::HiddenQueue> _innerQueue; 

搜索表单PIMPL ideom或d,指针

+0

不要将'auto_ptr'用于Pimpl成语,其奇怪的复制/分配语义更麻烦,因为它们是值得的。 'unique_ptr'或'scoped_ptr'好得多,如果需要的话,你可以编写一个非常简单的类。 – 2010-05-11 16:48:07

+0

'unique_ptr'只带有C++ 0x,'scoped_ptr'需要提升。 'auto_ptr'存在于任何地方。另外,当你的类不可复制时,使用'auto_ptr'更好 - 换句话说:你需要智能指针,标准C++只提供'auto_ptr' – Artyom 2010-05-11 19:08:03

相关问题