Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/144.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 多个Pimpl类相互使用_C++_Pimpl Idiom - Fatal编程技术网

C++ 多个Pimpl类相互使用

C++ 多个Pimpl类相互使用,c++,pimpl-idiom,C++,Pimpl Idiom,我通过pimpl向用户公开了三个类。模型是一个数据容器,可以从文件中读取和写入数据。操纵器是一个对象,可以加载模型,执行更改并将其作为新的模型返回。消费者加载模型,并允许用户使用该模型进行操作(读取其属性、打印等) 显然,这是行不通的。如何解决这个问题?pimpl是正确的解决方案吗 编辑:我的同事提出了以下建议: class Consumer { Consumer(Model &model); void loadModel(Model &model); v

我通过pimpl向用户公开了三个类。
模型
是一个数据容器,可以从文件中读取和写入数据。
操纵器
是一个对象,可以加载
模型
,执行更改并将其作为新的
模型
返回。
消费者
加载
模型
,并允许用户使用该模型进行操作(读取其属性、打印等)

显然,这是行不通的。如何解决这个问题?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());
}
类消费者{
消费者(模型和模型);
空隙荷载模型(模型和模型);
无效剂量();
私人:
类ConsumerImpl;
std::唯一的\u ptr mImpl;
};
类模型{
模型(std::字符串和文件名);
void-toFile(标准::字符串和文件名);
私人:
void*getObjectPtr();
类ModelImpl;
std::唯一的\u ptr mImpl;
朋友消费者;
};
void*Model::Model::getObjectPtr(){
返回mImpl->getObjectPtr();
}
类模型::ModelImpl{
公众:
//    [...]
void*getObjectPtr();
私人:
分泌型mData;
};
void*Model::ModelImpl::getObjectPtr(){
返回静态\u转换(&mData);
}
//从消费者处访问模型的内部数据:
void Consumer::ConsumerImpl::doSomething(){
SecretInternalType*data=static_cast(mModel->getObjectPtr());
}
基本上,模型有一个方法返回一个指向(隐藏)内部数据的空指针。使用者可以获取该指针,将其转换回正确的类型并访问数据。要使其仅可从Consumer类访问,该方法是私有的,但对Consumer来说是
friends


我实现了这个方法,它对我很有效。我仍然很好奇您对它的看法,以及是否存在任何问题。

您面临的问题实际上与Pimpl习语无关-假设您删除了代码片段中与Pimpl相关的部分,问题仍然是由于需要访问模型(或ModelImpl)实例的私有表示而导致的。这就是我试图处理这种情况的方式:

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

无论对设计应用什么更改,您仍然可以选择是否将Pimpl习惯用法用于转发方法。最后一个建议是:不要声明一个类
friend
——这可能是相当固执己见的,但您的场景并不表明这样一个强耦合是必要的。

您所面临的问题与Pimpl习语并没有真正的联系——假设您删除了代码片段中与Pimpl相关的部分,问题仍然是由于需要访问模型(或ModelImpl)实例的私有表示而导致的。这就是我试图处理这种情况的方式:

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

无论对设计应用什么更改,您仍然可以选择是否将Pimpl习惯用法用于转发方法。最后一个建议是:不要声明其中一个类
friend
——这可能是相当自以为是的,但您的场景并不表明需要如此强的耦合。

Pimpl可能是正确的选择,但如果您需要访问其他类的私有数据,那么设计可能在其他方面存在缺陷?这是可能的。我确信这是一件很普通的事情,但是我只有几个月的C++经验,我仍然在为许多设计选择而奋斗。有什么办法可以改进我的设计吗?如果它是我的朋友,它只需要访问
mImpl
,不需要使用void*。没错,这很好。我想我会选择这个解决方案。Pimpl可能是正确的选择,但也许设计在ot中有缺陷
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());
}