PIMPL习惯用法,用于指向C ++中的类的指针

时间:2018-11-13 19:26:59

标签: c++ c++11 pointers pimpl-idiom

我有一个适用于两个程序(ProgramAProgramB)的工作界面,我希望尽可能提高两个程序的解耦。我要介绍的情况是从ProgramAProgramBCompute_Prop)的类进行调用,该类只能使用一些我现在不提前使用的参数来初始化。因此,我在标题中使用了一个指针。目前,我有这样的事情:

界面。h

#include "programB.h" // loads Compute_Prop

class Compute {
  public:
    Compute();
    Compute(targ1 arg1, targ2 arg2);
    ~Compute();
    // some methods ...
  private:
    Compute_Prop* compute;
};

interface.cpp

#include "programB.h"
#include "interface.h"

#include "programA.h"

Compute::Compute() = default;

Compute::~Compute() {                                                                                                     
    delete compute;                                                                                                                                                                                                                                                                                                                                                                   
}

Compute::Compute(arg1, arg2) {

  // do something ... to get data

  compute = new Compute_Prop( &data, arg2 );
}

然后,我尝试使用以下内容模仿PIMPL习惯用语

界面。h

#include "programB.h" // loads Compute_Prop

class Compute {
  public:
    Compute();
    Compute(targ1 arg1, targ2 arg2);
    ~Compute();
    // some methods ...
  private:
    class PIMPL;
    PIMPL* compute;
};

interface.cpp

#include "programB.h"
#include "interface.h"

#include "programA.h"

Compute::PIMPL = Compute_Prop;

Compute::Compute() = default;

Compute::~Compute() {                                                                             
    delete compute;                                                                                                                                                                     
}

Compute::Compute(arg1, arg2) {

  // do something ... to get data

  compute = new Compute_Prop( &data, arg2 );
}

但是编译器说:

error: expected unqualified-id
  Compute::PIMPL = Compute_Prop;
                 ^

我想这与Compute_Prop没有关系 一个空的构造函数。我无法提出可行的建议。我该怎么办?像指针一样的指针,也许吗?作为限制,我不能修改programB

注意:从上面可能已经很清楚了,我对低级C ++ / C的了解很少。

编辑:我介绍了@ n.m建议的更正。和@Matthieu Brucher

2 个答案:

答案 0 :(得分:1)

您的实现应使用接口(或实际上只有抽象方法的类)作为基类。 您不能在C ++中分配类型。您只能创建typedef和别名,例如:

using PIMPLType = Compute_Prop;

但是,这不适用于您的情况。 这是应该如何实施(还有可能的多种实施方式):

class IImplementation
{
public:
    virtual void saySomething() = 0;
};

class ImplementationA : public IImplementation
{
public:
    virtual void saySomething() override {
        std::cout << "A";
    }
};
class ImplementationB : public IImplementation
{
public:
    virtual void saySomething() override {
        std::cout << "B";
    }
};

class Foo {
    IImplementation *pimpl;
public:
    Foo()
        : pimpl(new ImplementationA)
    {}

    ~Foo() { delete pimpl; }

    void saySomething() {
         pimpl->saySomething();
    }
};

答案 1 :(得分:0)

我可能遇到一个简单的解决方案。我将其发布在这里,以便您可以判断它是否足够,甚至可以改进---当然。我坚信不需要运行时多态,甚至不需要多态。无论如何,成员变量compute将是指向Compute_Prop类型的指针。然后,鉴于此处的性能至关重要:为什么要运行虚拟成员函数的额外开销?

这里的重点是要实现一种隐藏Compute_Prop的实现而不会降低性能的实现。怎么样?此特定解决方案使用模板化的类,然后使用显式实例化。关键是实例化可以在实现中完成。从a Fluent C++ blog post得到了它。此外,this post还提供了有关应如何实现的提示。原型将是:

界面。h

template <typename T>
class Compute {
  public:
    Compute();
    Compute(targ1 arg1, targ2 arg2);
    ~Compute();
    // some methods ...
  private:
    T* compute; // No need to state that is going to be T:=Compute_Prop
};

interface_impl.h

#include "interface.h"    
#include "programA.h"

template <typename T>
Compute::Compute() = default;

template <typename T>
Compute::~Compute() {                                                                                                              
    delete compute;                                                                                                                                                                                                                                                                                                                                                                
}

template <typename T>
Compute::Compute(arg1, arg2) {

  // do something ... to get data

  compute = new T( &data, arg2 );
}

interface.cpp

 #include "interface.h"
 #include "interface_impl.h"
 #include "programA.h"
 #include "programB.h" // loads Compute_Prop

 int main(int argc, char** argv) {

   template class Compute<Compute_Prop>;

 }

另一个相关的question可能对同样困境的人有用。