使用命名空间隐藏内部类实现

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{};
};
3个回答

6
编译器需要通过查看对象所在的头文件来了解其精确的内存布局。
您的代码表明类MyQueue具有InnerQueue类型的成员,该成员将成为MyQueue对象内存布局的一部分。因此,为了推断MyQueue的内存布局,它需要知道InnerQueue的内存布局。但是它并不知道,因为您说“噢,好吧,它在别处定义”。
您正在尝试的内容与“PIMPL 惯用语”/“编译器防火墙”技术密切相关。
要解决这个问题,您必须在头文件中包含HiddenQueue.h,或声明_innerqueue为指针。
class myQueue {

public:
    myQueue();

private:

    inner::HiddenQueue* _pinnerQueue;
};

使用指针是可能的,因为指针具有已知的内存大小(取决于您的目标架构),因此编译器不需要看到完整的HiddenQueue声明。

+1 为 PIMPL。这是一个造词者的文章链接:http://www.gotw.ca/gotw/024.htm - Emile Cormier
总的来说,PIMPL会带来一些运行时速度成本,并为您提供维护和编译速度方面的收益。不可否认,在一般情况下,运行时速度成本并不是一个问题(当它确实是一个问题时,您可能知道它很重要),但在我看来,在代码库小于某个特定大小时,没有必要使用PIMPL。 - Jon

1

你需要提供指向 _innetQueue 的指针,而不是对象本身:

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

搜索表单 Pimpl Ideom 或 D-Pointer


不要在Pimpl惯用法中使用auto_ptr,它奇怪的复制/赋值语义会带来更多麻烦。unique_ptrscoped_ptr更好,如果必要,您可以编写一个非常简单的类。 - Matthieu M.
unique_ptr 只在 C++0x 中提供,scoped_ptr 需要 boost。auto_ptr 则可以在任何地方使用。此外,当你的类不可复制时,使用 auto_ptr 是完全可以的——换句话说:你需要智能指针,而标准 C++ 仅提供 auto_ptr - Artyom

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接