档案a.hpp
:
class a;
typedef boost::shared_ptr<a> aPtr
class a{
public:
static aPtr CreateImp();
virtual void Foo() = 0 ;
....
};
档案aImp.hpp
:
class aImp : public a{
virtual void Foo();
};
档案aImp.cpp
:
aPtr a::CreateImp()
{
return aPtr(new aImp());
}
void aImp::Foo(){}
客户端必须使用CreateImp
获取指向a
的指针,并且不能使用a
其他方式。
您对此实施有何看法?
您如何看待这种实施?
答案 0 :(得分:7)
如果Factory Method设计模式,这看起来像是正常的实现。 boost::shared_ptr
的返回只会让程序员在内存管理和异常安全方面更容易使用这个API,并且可以防止调用函数和忽略返回值等简单错误。
如果这是基类的唯一实现,则可能是作者的目标是pimpl idiom隐藏实现细节和/或减少编译时依赖性。
答案 1 :(得分:2)
如果意图使用PIMPL习语,那么它不是最惯用的方式。继承是C ++中第二强的耦合关系,如果有其他解决方案可用,则应该避免(即组合)。
现在,可能还有其他要求强制使用动态分配和/或使用特定类型的智能指针,但是根据您提供的信息,我将以通用方式实现PIMPL习惯用法: / p>
// .h
class a {
public:
~a(); // implement it in .cpp where a::impl is defined
void op();
private:
class impl;
std::auto_ptr<impl> pimpl;
};
// .cpp
class a::impl {
public:
void op();
};
a::~a() {}
void a::op() { pimpl->op(); }
使用继承的唯一(dis)优势是运行时调度机制将为您调用实现方法,并且您不需要实现转发调用(示例中为a::op()
)。另一方面,您要在每个操作中支付虚拟调度机制的成本,并将类的使用限制在堆中(您不能在堆栈中创建a
的实例,您必须调用工厂函数动态创建对象。
在界面中使用shared_ptr
时,如果可能的话,我会尽量避免使用{给用户自由选择)。在这种特殊情况下,似乎对象实际上并不是 shared (创建者函数创建一个实例并返回指针,忘记它),所以最好有一个智能指针,允许转让所有权(std::auto_ptr
,或者较新的unique_ptr
可以执行此操作),因为使用shared_ptr
会将此决定强加给您的用户。
(注意:删除它,因为评论使其无用)
答案 2 :(得分:1)
看起来很好的封装,虽然我实际上没有看到任何阻止使用的东西。 (例如,私有构造函数和朋友类aImp)。
除了aImp.cpp本身之外,没有使用类a的编译单元将具有任何实现细节的知识。因此,对aImp.hpp的更改不会导致整个项目的重新编译。这既加速了重新编译又防止了耦合,它有助于维护很多。
OTOH,aImp.hpp中实现的任何内容现在都无法内联,因此运行时性能可能会受到影响,除非您的编译器具有类似于Visual C ++“链接时代码生成”的东西(这几乎取消任何增益)从封装中建立速度。)就智能指针而言,这取决于项目编码标准(是否在任何地方使用升压指针等)。