我最近从 Java 和 Ruby 切换回 C++,令我惊讶的是,当我更改私有方法的方法签名时,我必须重新编译使用公共接口的文件,因为私有部分也在 .h 文件中。
我很快想出了一个解决方案,我猜这是 Java 程序员的典型解决方案:接口(= 纯虚拟基类)。例如:
香蕉树.h:
class Banana;
class BananaTree
{
public:
virtual Banana* getBanana(std::string const& name) = 0;
static BananaTree* create(std::string const& name);
};
香蕉树.cpp:
class BananaTreeImpl : public BananaTree
{
private:
string name;
Banana* findBanana(string const& name)
{
return //obtain banana, somehow;
}
public:
BananaTreeImpl(string name)
: name(name)
{}
virtual Banana* getBanana(string const& name)
{
return findBanana(name);
}
};
BananaTree* BananaTree::create(string const& name)
{
return new BananaTreeImpl(name);
}
这里唯一的麻烦是我不能使用new
,而必须调用BananaTree::create()
. 我不认为这真的是一个问题,特别是因为我预计无论如何都会大量使用工厂。
然而,现在,C++ 成名的智者提出了另一种解决方案,即pImpl idiom。这样,如果我理解正确,我的代码将如下所示:
香蕉树.h:
class BananaTree
{
public:
Banana* addStep(std::string const& name);
private:
struct Impl;
shared_ptr<Impl> pimpl_;
};
香蕉树.cpp:
struct BananaTree::Impl
{
string name;
Banana* findBanana(string const& name)
{
return //obtain banana, somehow;
}
Banana* getBanana(string const& name)
{
return findBanana(name);
}
Impl(string const& name) : name(name) {}
}
BananaTree::BananaTree(string const& name)
: pimpl_(shared_ptr<Impl>(new Impl(name)))
{}
Banana* BananaTree::getBanana(string const& name)
{
return pimpl_->getBanana(name);
}
这意味着我必须为 的每个公共方法实现装饰器风格的转发方法BananaTree
,在这种情况下getBanana
。这听起来像是增加了我不想要求的复杂性和维护工作。
那么,现在的问题是:纯虚拟类方法有什么问题?为什么 pImpl 方法的文档记录得这么好?我错过了什么吗?