我有三个通过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隐藏了它们: / p>
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类进行访问,该方法是私有方法,但对于Consumer是friends
。
我实现了这种方法,并且对我有用。不过,我仍然很好奇您对此有何看法以及是否有任何问题。
答案 0 :(得分:3)
您面临的问题与Pimpl习惯用法并没有真正的关系-假设您擦除了代码片段中与pimpl相关的部分,该问题与由于需要访问模型的私有表示而导致的问题相同(或ModelImpl)实例。这就是我尝试解决这种情况的方式:
无论您对设计应用了什么更改,您仍然可以选择是否将Pimpl惯用语与转发方法一起使用。最后一个建议是:不要声明friend
类之一-这可能是很有道理的,但是您的情况并不意味着需要这样的强耦合。