如何在PIMPL设计模式中调用参数化构造函数?

时间:2013-07-26 06:33:58

标签: c++

如何将PIMPL设计用于参数化构造函数?

/* ProcessImpl.h */
class ProcessImpl {
public :ProcessImpl(); 
    ProcessImpl(ProcessID thirdParty_pid);
    ~ProcessImpl();
} 

/* Process.h */
class Process { 
public:virtual ~Process () {}; 
    Process();
    Process(ProcessID thirdParty_pid);

protected: 
    void createImpl(); 
private: 
    ProcessImpl * _impl; 
}

/* Process.cpp */
Process::Process():_impl(NULL) {
}

Process::Process(ProcessID thirdParty_pid) {        
    createImpl();
    _impl->ProcessImpl(ldframework::ProcessID thirdParty_pid);
}

void Process::createImpl(){
    if(this->_impl == NULL) {
        this->_impl = new ProcessImpl();
    }
 }

当我编译这个时,我收到错误:      Process.cpp:错误:无效使用类ProcessImpl
     这是抛出线的错误_impl-> ProcessImpl(ldframework :: ProcessID thirdParty_pid)

Please help

2 个答案:

答案 0 :(得分:1)

由于您的代码无效C ++,我不会对您的实际实现做出结论,因此我将从头开始:

如果类具有参数化构造函数,则需要参数来直接或间接初始化类成员和基类。由于pimpl'd类没有自己的数据成员(pimpl除外),因此仅需要初始化实现类的构造函数参数。
pimpl习语的实现有两个极端:

  1. 所有逻辑都进入实现类,外部类只是一个愚蠢的fassade,转发任何对pimpl的调用。
  2. 逻辑仍然在外层,pimpl只是一堆愚蠢的数据。
  3. 当然,在实践中,两者之间的任何事情都是可能的。

    在case 1中,外部类的构造函数签名应该与实现类'构造函数的签名相同,并且只是将任何参数传递给pimpl构造函数:

    <强> foo.h中

    class Foo {
      struct FooImpl;
      std::unique_ptr<FooImpl> pImpl;
    public:
      ~Foo();
      Foo(A const& a);
      Foo(B b, C* c, D& d);
    };
    

    <强> Foo.cpp中

    struct Foo::FooImpl {
      FooImpl(A const& a);
      FooImpl(B b, C* c, D& d);
      /* Logic goes here */
    };
    
    Foo::~Foo() {} //defined here for correct deletion of the unique_ptr
    
    Foo::Foo(A const& a)
      : pImpl(std::make_unique<FooImpl>(a))
    {}
    
    Foo::Foo(B b, C* c, D& d)
      : pImpl(std::make_unique<FooImpl>(std::move(b), c, d))
    {}
    

    合:

    1. 对类和pimpl-class使用相同的构造函数签名,每个类构造函数只调用相应的pimpl-constructor
    2. 引用或指针获取的参数按原样传递给pimpl构造函数
    3. 按值获取的参数将移至pimpl构造函数(转发)
    4. 这是最简单的解决方案,其中构造函数逻辑完全在实现类中实现。

      在另一种情况下,pimpl类只是一个数据包,你将在外部类`构造函数中有逻辑,如下所示:

      struct Foo::FooImpl {
        FooImpl(A const& a, B b, E e, F f);
        A a;
      };
      
      Foo::Foo(B b, C* c, D& d)
        : pImpl(std::make_unique<FooImpl>(A(), std::move(b), calcE(c,d), getSomeF())
      {
        pImpl->a = someValueForA();
      }
      

      你知道,实现构造函数的策略取决于你完全实现pimpl习语的策略。只需确保在将逻辑委托给pimpl类或将其保留在主类中时,您都会保持一致。

答案 1 :(得分:0)

只需在构造函数中构造pimpl。

请注意,您还应该实现复制构造函数和赋值运算符,因为复制对象将导致两个副本被销毁时出现未定义的行为。

理想情况下,pimpl应始终有效以避免检查它是否始终有效,但是按照您的代码,您可能会有以下内容:

class Process { 
public:
    virtual ~Process () {
    }; 
    Process() {
        // Ideally the impl_ pointer should be intialized to avoid 
        // having to check it in every function that uses it..
    }
    Process(ProcessID pid) {
        impl_.reset(new ProcessImpl(pid));
    }
    Process(Process const& rhs) {
        if (rhs.impl_.get()) {
            impl_.reset(new ProcessImpl(*rhs.impl_));
        }
    }
    Process& operator=(Process const& rhs) {
        if (this != &rhs) {
            if (rhs.impl_.get()) {
                impl_.reset(new ProcessImpl(*rhs.impl_));
            }
            else {
                impl_.reset();
            }
        }
        return *this;
    }

private: 
    std::unique_ptr<ProcessImpl> impl_; 
};