gpt4 book ai didi

c++ - 多个 Pimpl 类互相使用

转载 作者:行者123 更新时间:2023-11-27 23:45:24 26 4
gpt4 key购买 nike

我通过 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 , ManipulatorConsumer和标准的 C++ 类型。

我在这里遇到的问题是在实现中 ConsumerImplManipulatorImpl : 在那些类中,我必须访问 ModelImpl 的底层数据结构,但 pimpl 隐藏了它们:

Consumer::ConsumerImpl::loadModel(Model model) {
auto someModelValue = model.mImpl->someInternalValue;
}

显然这是行不通的。如何解决这个问题? pimpl 是这里的正确解决方案吗?

编辑:我的同事想出了这个:

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());
}

基本上,模型有一个返回指向(隐藏)内部数据的空指针的方法。消费者可以获得这个指针,将其转换回正确的类型并访问数据。为了使其只能从 Consumer 类访问,该方法是私有(private)的,但 friends与消费者。

我实现了这种方法,它对我很有效。我仍然很好奇你是怎么想的,是否有任何问题。

最佳答案

您面临的问题与 Pimpl 习语并不真正相关 - 假设您删除了代码段中与 pimpl 相关的部分,问题仍然存在,因为它是由需要访问模型的私有(private)表示(或ModelImpl) 实例。这就是我尝试处理这种情况的方式:

  • 定义一个操作列表,这些操作对于消费者实例在模型实例上调用是有意义的。这些应该是模型公共(public)接口(interface)的一部分。对模型和操纵器之间的关系执行相同的操作。如果这会使您的模型接口(interface)过于困惑,请将其拆分为两个单独的抽象类,让模型实现从两者继承,并让 Consumer/Maninpulator 在为它们准备的基类接口(interface)上运行。
  • 重新考虑模型的哪些部分值得隐藏。如果模型拥有一些需要从消费者访问的容器,请公开它(有效 STL,第 2 项),通过适当的方法进行读取访问应该没问题。
  • 如果 Consumer 对象仍然需要更多信息,他们自己的角色可能不仅仅是普通消费者,那么他们实现的某些部分是否应该在另一个类或模型中实现?
  • 引入一个 (n)(抽象)类,用于模型和消费者之间的数据交换。将此从 Consumer 传递给 Model,让 Model 选择将哪些信息传递给中间层。但这已经引入了一定程度的复杂性,而这些复杂性可能是完全没有必要的。

无论您对设计进行何种更改,您仍然可以选择是否将 Pimpl 习惯用法与转发方法一起使用。最后一个建议:不要声明其中一个类 friend - 这可能很固执己见,但您的场景并不表明这种强耦合是必要的。

关于c++ - 多个 Pimpl 类互相使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51101999/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com