在某种程度上可以实现以下目标:
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*
并将其投射..
答案 0 :(得分:9)
实际上,甚至可以完全隐藏用户:
// Foo.hpp
class Foo {
public:
//...
private:
struct Impl;
Impl* _impl;
};
// Foo.cpp
struct Foo::Impl {
// stuff
};
我只想提醒你:
有一些方法可以自动化PIMPL,代价是一些黑魔法(类似于std::shared_ptr
所做的那样)。
答案 1 :(得分:5)
作为@Angew答案的替代方案,如果不应该让x类用户知道名称 concrete_x
,那么你可以这样做:
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_; }
答案 2 :(得分:2)
这仅在前向声明声明类的实际名称时才有效。因此,要么将 x.hpp 更改为:
class concrete_x;
class x {
public:
//methods...
private:
concrete_x* impl_;
};
或使用名称x_impl
作为标题<concrete_x>
中定义的类。
答案 3 :(得分:0)
这就是接口的用途。在共享头文件中定义接口(纯虚拟类)并将其提供给用户。从接口继承您的具体类并将其放在非共享头文件中。在cpp文件中实现具体类(您甚至可以在cpp中定义具体类)。