是否有可能,以实现以下目标:
x.hpp - 许多其他类都包含此文件
class x_impl; //forward declare
class x {
public:
//methods...
private:
x_impl* impl_;
};
x.cpp - 实施
#include <conrete_x>
typedef concrete_x x_impl; //obviously this doesn't work
//implementation of methods...
基本上,我希望用户包含该文件 x.hpp,但不知道 conrete_x.hpp 头。
既然我可以使用 concrete_x
只有指针并且它只作为私有数据成员出现,前向声明应该足以让编译器知道准备多少空间。它看起来很像着名的“pimpl成语”。
你能帮我解决这个问题吗?
PS。我不想用 void*
把它扔到...
实际上,甚至可以完全隐藏用户:
// Foo.hpp
class Foo {
public:
//...
private:
struct Impl;
Impl* _impl;
};
// Foo.cpp
struct Foo::Impl {
// stuff
};
我想提醒你的是:
- 你需要写一个适当的析构函数
- 因此,您还需要一个适当的复制构造函数,复制赋值运算符,移动构造函数和移动赋值运算符
有一些方法可以自动化PIMPL,代价是一些黑魔法(类似于什么 std::shared_ptr
一样)。
作为@Angew的答案的替代,如果名称 concrete_x
不应该让x类用户知道,你可以这样做:
在 x.hpp
class x_impl;
class x {
public:
x();
~x();
//methods...
private:
x_impl* impl_;
};
在 x.cpp
#include <concrete_x>
class x_impl : public concrete_x { };
x:x() : impl_(new x_impl) {}
x:~x() { delete impl_; }
这仅在前向声明声明类的实际名称时才有效。所以要么改变 x.hpp 至:
class concrete_x;
class x {
public:
//methods...
private:
concrete_x* impl_;
};
或使用名称 x_impl
对于标头中定义的类 <concrete_x>
。
这就是接口的用途。在共享头文件中定义接口(纯虚拟类)并将其提供给用户。从接口继承您的具体类并将其放在非共享头文件中。在cpp文件中实现具体类(甚至可以在cpp中定义具体类)。