多个 Pimppl 类相互使用
Multiple Pimpl-classes using each other
我有三个类,我通过pimpl向用户公开。Model
是可以读取和写入文件的数据容器。Manipulator
是一个对象,可以加载Model
,执行更改并将其作为新Model
返回。Consumer
加载Model
并允许用户使用它进行操作(读取其属性,打印它等(。
class Model {
Model(std::string &filename);
void toFile(std::string &filename);
private:
class ModelImpl;
std::unique_ptr<ModelImpl> mImpl;
};
class Manipulator {
Manipulator(Model &model);
Model alterModel(...);
private:
class ManipulatorImpl;
std::unique_ptr<ManipulatorImpl> mImpl;
};
class Consumer {
Consumer(Model &model);
void loadModel(Model &model);
void doSomething();
private:
class ConsumerImpl;
std::unique_ptr<ConsumerImpl> mImpl;
};
使用pimpl 的原因主要是为了隐藏Model
使用的内部数据类型。用户唯一可见的类型应该是Model
、Manipulator
和Consumer
以及标准 c++ 类型。
我在这里遇到的问题是在实现ConsumerImpl
和ManipulatorImpl
:在这些类中,我必须访问ModelImpl
的底层数据结构,但 pimpl 隐藏了它们:
Consumer::ConsumerImpl::loadModel(Model model) {
auto someModelValue = model.mImpl->someInternalValue;
}
显然这是行不通的。如何解决这个问题?痘痘是这里的正确解决方案吗?
编辑:我的同事想出了这个:
class Consumer {
Consumer(Model &model);
void loadModel(Model &model);
void doSomething();
private:
class ConsumerImpl;
std::unique_ptr<ConsumerImpl> mImpl;
};
class Model {
Model(std::string &filename);
void toFile(std::string &filename);
private:
void *getObjectPtr();
class ModelImpl;
std::unique_ptr<ModelImpl> mImpl;
friend Consumer;
};
void *Model::Model::getObjectPtr() {
return mImpl->getObjectPtr();
}
class Model::ModelImpl {
public:
// [...]
void *getObjectPtr();
private:
SecretInternalType mData;
};
void *Model::ModelImpl::getObjectPtr() {
return static_cast<void*>(&mData);
}
// Access the internal data of Model from Consumer:
void Consumer::ConsumerImpl::doSomething() {
SecretInternalType* data = static_cast<SecretInternalType*>(mModel->getObjectPtr());
}
基本上,模型有一个返回指向(隐藏(内部数据的 void 指针的方法。使用者可以获取此指针,将其转换回正确的类型并访问数据。若要使其只能从 Consumer 类访问,该方法是私有的,但与 Consumerfriends
。
我实施了这种方法,它对我有用。我仍然很好奇你怎么看,是否有任何问题。
您面临的问题与 Pimpl 习语并不真正相关 - 假设您删除了代码段中与 pimpl 相关的部分,问题保持不变,因为它是由需要访问模型(或 ModelImpl(实例的私有表示引起的。这就是我尝试处理这种情况的方式:
- 定义对使用者实例在模型实例上调用有意义的操作列表。这些应该是模型公共接口的一部分。对模型和操纵器之间的关系执行相同的操作。如果这会使您的 Model 接口过于混乱,请将其拆分为两个单独的抽象类,让 Model 实现继承两者,并且 Consumer/Maninpulator 在为它们准备的基类接口上运行。
- 重新考虑模型的哪些部分值得隐藏。如果 Model 拥有某个需要从使用者访问的容器,请公开它(有效 STL,第 2 项(,通过适当的方法进行读取访问应该没问题。
- 如果 Consumer 对象仍然需要更多信息,那么它们自己的角色可能不仅仅是普通的消费者,那么也许它们实现的某些部分应该在另一个类或模型中实现?
- 引入一个(n((抽象(类,用于模型和消费者之间的数据交换。将此从消费者传递到模型,让模型选择要将哪些信息传递给中间层。但这已经引入了一定程度的复杂性,这可能是非常不必要的。
无论您对设计进行何种更改,您仍然可以选择是否将 Pimpl 习惯用法与转发方法一起使用。最后一个建议:不要friend
声明其中一个类 - 这可能是非常固执己见的,但您的场景并不表明这种强耦合是必要的。
相关文章:
- 处理多个异常集合的C++方法
- 尝试通过多个向量访问变量时,向量下标超出范围
- Ardunio UNO解决了多个重叠的定时器循环
- 是否可以通过C++扩展强制多个python进程共享同一内存
- 基于多个条件处理地图中的所有元素
- 为多个会话保留XPtr
- IPC使用多个管道和分支进程来运行Python程序
- 通过套接字[TCP]传输数据 如何在C / C ++中打包多个整数并使用send() recv()传输数据
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- Visual Studio 2019:插入多个C++风格的单行注释
- 扩展光电二极管探测器以支持多个传感器
- 是否可以使用winusb同时与多个相同的usb设备进行通信
- boost::asio如何生成多个协同程序,然后加入它们
- 使用命名空间时出现多个定义错误
- 我需要将多个函数组合为一个函数
- 用于矢量处理的多个线程
- 多个If语句与使用逻辑运算符计算条件的单个语句的比较
- MPI突然停止了对多个核心的操作
- 在C++中,如何通过几种类型从元组中选择多个元素
- 多个 Pimppl 类相互使用