C++ 中指向 class 的指针的 PIMPL 习语
PIMPL idiom for a pointer to a class in C++
我有两个程序(ProgramA
和 ProgramB
)的工作界面,我想尽可能地改进这两个程序的解耦。我想介绍的案例是从 ProgramA
调用 ProgramB
(Compute_Prop
) 到 class,它只能用一些我现在没有的参数初始化提前。因此,我在 header 中使用了一个指针。目前,我有这样的东西:
interface.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的成语
interface.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
您的实现应该使用一个接口(或者实际上 class 只有抽象方法)作为基础 class。
您不能在 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();
}
};
我可能遇到了一个简单的解决方案。我 post 在这里,所以你可以判断它是否足够,或者即使它可以改进 --- 当然。我确信不需要运行时多态性,甚至不需要多态性。无论如何,成员变量 compute
将成为指向 Compute_Prop
类型的指针。然后,鉴于这里的性能至关重要:为什么 运行 虚拟成员函数的额外开销?
这里的重点是实现隐藏 Compute_Prop
的包含而不损失性能。如何?这个特定的解决方案使用模板化 class 然后显式实例化。重点是可以在实现中进行实例化。从 a Fluent C++ blog post. Also, this post 得到它有关于如何完成实施的提示。原型是:
interface.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 可能对那些有同样困境的人有用。
我有两个程序(ProgramA
和 ProgramB
)的工作界面,我想尽可能地改进这两个程序的解耦。我想介绍的案例是从 ProgramA
调用 ProgramB
(Compute_Prop
) 到 class,它只能用一些我现在没有的参数初始化提前。因此,我在 header 中使用了一个指针。目前,我有这样的东西:
interface.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的成语
interface.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
您的实现应该使用一个接口(或者实际上 class 只有抽象方法)作为基础 class。 您不能在 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();
}
};
我可能遇到了一个简单的解决方案。我 post 在这里,所以你可以判断它是否足够,或者即使它可以改进 --- 当然。我确信不需要运行时多态性,甚至不需要多态性。无论如何,成员变量 compute
将成为指向 Compute_Prop
类型的指针。然后,鉴于这里的性能至关重要:为什么 运行 虚拟成员函数的额外开销?
这里的重点是实现隐藏 Compute_Prop
的包含而不损失性能。如何?这个特定的解决方案使用模板化 class 然后显式实例化。重点是可以在实现中进行实例化。从 a Fluent C++ blog post. Also, this post 得到它有关于如何完成实施的提示。原型是:
interface.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 可能对那些有同样困境的人有用。