0

如何将 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
4

2 回答 2

1

由于您的代码不是有效的 C++,因此我不会对您的实际实现下结论,所以我将从头开始:

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

  1. 所有的逻辑都进入了实现类,外部类只是一个愚蠢的fassade,将任何调用转发给pimpl。
  2. 逻辑保留在外部类中,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);
};

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 构造函数(转发)

这是最简单的可能解决方案,其中构造器逻辑完全在实现类中实现。

在另一种情况下,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 idiom 的策略。只需确保您在将逻辑委托给 pimpl 类或将其留在主类中都保持一致。

于 2013-07-26T07:57:00.200 回答
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_; 
};
于 2013-07-26T07:38:46.743 回答