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

C++ 如何在PIMPL设计模式中调用参数化构造函数?,c++,C++,如何使用参数化构造函数的PIMPL设计 /* ProcessImpl.h */ class ProcessImpl { public :ProcessImpl(); ProcessImpl(ProcessID thirdParty_pid); ~ProcessImpl(); } /* Process.h */ class Process { public:virtual ~Process () {}; Process(); Process(Process

如何使用参数化构造函数的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)


只需在构造函数中构造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_; 
};
类进程{
公众:
虚拟进程(){
}; 
过程(){
//理想情况下,应初始化impl_uu指针以避免
//必须在每个使用它的函数中检查它。。
}
进程(进程ID pid){
执行重置(新进程执行(pid));
}
工艺(工艺常数和rhs){
if(rhs.impl_u2;.get()){
执行重置(新的ProcessImpl(*rhs.impl));
}
}
流程和操作员=(流程常量和rhs){
如果(此!=&rhs){
if(rhs.impl_u2;.get()){
执行重置(新的ProcessImpl(*rhs.impl));
}
否则{
impl_.reset();
}
}
归还*这个;
}
私人:
std::唯一\u ptr impl;
};

<代码> > p>由于您的代码无效,C++不会对您的实际实现作出结论,所以我将从一开始就开始:

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

  • 所有逻辑都进入实现类,外部类只是一个哑fassade,将所有调用转发给pimpl
  • 逻辑保留在外部类中,pimpl只是一个哑数据包
  • 当然,在实践中,介于两者之间的任何事情都是可能的

    在案例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);
    };
    
    class-Foo{
    结构FooImpl;
    std::唯一的ptr pImpl;
    公众:
    ~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))
    {}
    
    struct Foo::FooImpl{
    FooImpl(const&A);
    FooImpl(B、B、C*C、D&D);
    /*逻辑就在这里*/
    };
    Foo::~Foo(){}//在此处定义,用于正确删除唯一的\u ptr
    Foo::Foo(const&A)
    :pImpl(标准::使_唯一(a))
    {}
    Foo::Foo(B B,C*C,D&D)
    :pImpl(std::make_unique(std::move(b),c,d))
    {}
    
    一起:

  • 对类和pimpl类使用相同的构造函数签名,每个类构造函数只调用相应的pimpl构造函数
  • 引用或指针获取的参数按原样传递给pimpl构造函数
  • 值获取的参数被移动到pimpl构造函数(转发)
  • 这是最简单的解决方案,其中构造函数逻辑完全在实现类内部实现

    在另一种情况下,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();
    }
    
    struct Foo::FooImpl{
    FooImpl(A const&A、B B、E、F);
    A A;
    };
    Foo::Foo(B B,C*C,D&D)
    :pImpl(std::make_unique(A(),std::move(b),calcE(c,d),getSomeF())
    {
    pImpl->a=someValueForA();
    }
    

    您知道,实现构造函数的策略取决于您一起实现pimpl习惯用法的策略。只需确保您在将逻辑委托给pimpl类或将其保留在主类中时有一定的一致性。

    给我们一个简单的示例,说明您已经尝试过但不起作用的方法。
    createImpl()
    是用来调用的?为什么不在
    进程的成员初始化列表中初始化
    \u impl
    ?这样您就可以简单地传递参数了。我已经完成了这个过程::Process():\u impl(NULL){}但是现在我想使用Process(ProcessID thirdParty_pid)并调用ProcessImpl(ProcessID thirdParty_pid);ldframework::Process::Process(ProcessID thirdParty_-pid){createImpl();_-impl>ProcessImpl::ProcessImpl(thirdParty_-pid);}如果我使用这个方法erro@Pete这取决于。流程类可能会使用特定于平台的标头和数据类型。封装这些依赖项(例如windows.h和其他丑陋的API)使用pimpl远离程序的其余部分并不坏。非常感谢您的响应。如果我使用它,我会收到以下错误。错误:类ProcessImpl没有名为resetit的成员正在调用reset()在std::auto_ptr上。从C++11开始,您的#include
    auto_ptr
    就已经被弃用了。
    unique_ptr
    没有双重删除的问题。我遵循了这个方法Process::Process(ProcessID thirdParty_pid){_impl->ProcessImpl(thirdParty_pid)}但我收到以下错误:类ProcessImpl的使用无效请响应。我尝试了“外部类的构造函数签名应与实现类的构造函数的签名相同,只需将任何参数传递给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();
    }