这是一个很好的代码(在阅读同事的代码时遇到)

时间:2010-03-21 20:57:04

标签: c++

档案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其他方式。 您对此实施有何看法? 您如何看待这种实施?

3 个答案:

答案 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 ++“链接时代码生成”的东西(这几乎取消任何增益)从封装中建立速度。)

就智能指针而言,这取决于项目编码标准(是否在任何地方使用升压指针等)。