命名构造函数和继承

时间:2009-02-12 08:42:49

标签: c++ inheritance constructor factory named

我正在研究C ++框架,并希望将自动内存管理应用于许多核心类。到目前为止,我有标准方法

class Foo 
{

public:

  static
  shared_ptr<Foo> init() 
  {
    return shared_ptr<Foo>(new Foo);
  }

  ~Foo() 
  {
  }

protected:

  Foo()
  {
  }

};


// Example of use
shared_ptr<Foo> f = Foo::init();

但是,当我将Foo子类化时,上面会中断,因为即使继承init(),它仍会返回shared_ptr<Foo>,其中包含指向Foo实例的指针。

有人能想到一个优雅的解决方案吗?我是否应该坚持(半)手动包装shared_ptr类的实例?这也可以在不声明新的命名构造函数的情况下公开参数化构造函数...

template <typename T>
shared_ptr<T> make_shared(T* ptr)
{
  return shared_ptr<T>(ptr)
}

// Example
shared_ptr<T> 
  f1 = make_shared(new Foo()),
  f2 = make_shared(new Foo(1,2));

8 个答案:

答案 0 :(得分:4)

我会尝试这样的事情:

template<class T>
class creator
{
  public:
    static shared_ptr<T> init()
    {
      return(shared_ptr<T>(new T));
    }
};

class A : public creator<A>
{
};

class B : public A, public creator<B>
{
  public:
    using make_shared<B>::init;
};

// example use
shared_ptr<A> a = A::init();
shared_ptr<B> b = B::init();

但与您提出的独立模板相比,这并不一定能为您节省一些时间。

编辑:我错过了之前的回答,这似乎是一样的想法。

答案 1 :(得分:3)

我不明白这实现了什么,你似乎没有使用这个init函数获得任何额外的内存管理,而只是简单地声明一个shared_ptr。

int main( void )
{
    shared_ptr<foo> a = foo::init();
    shared_ptr<foo> b( new foo );
}

有什么区别。 shared_ptr提供内存管理,而不是init中的任何内容。

答案 2 :(得分:2)

似乎目标是让类的用户不可能直接调用构造函数,并且只暴露返回shared_ptr的例程。

但是如果要应用此模式,则需要在所有子类中复制它。子类不能自动“继承”init(),因此init()仍然会调用子类构造函数,因为init()不是虚方法,而是在没有对象的情况下调用。

我会像往常一样暴露构造函数,只使用标准

shared_ptr<X> x = new X();

这可以降低认知负担,可读性和灵活性。无论如何,这就是我们在公司中使用引用计数对象进行编程的方式。

答案 3 :(得分:1)

怎么样......

template<typename Derived>
class Foo 
{
public:

    static shared_ptr<Derived> init() 
    {
        return shared_ptr<Derived>(new Derived);
    }

    ~Foo() 
    {
    }

protected:

    Foo()
    {
    }

};


class Bar : public Foo<Bar>
{
};

int _tmain(int argc, _TCHAR* argv[])
{
    shared_ptr<Bar> b = Foo<Bar>::init(); 
    return 0;
}

答案 4 :(得分:1)

为什么不在虚拟析构函数中引入公共基础,从中继承所有必需的类并简单地使用new?

答案 5 :(得分:1)

通过隐藏构造函数来强制使用shared_ptr创建对象通常不是一个好主意。我是根据个人经验在这里与内部公司lib合作完成的。如果您想确保人们总是包装他们分配的对象,只需确保存储这些类型实例的所有参数和成员都需要shared_ptrweak_ptr而不是裸指针或引用。您可能还希望从enable_shared_from_this派生这些类,因为在共享所有对象的系统中,您必须将this指针传递给其他对象的方法之一,并且由于它们的设计只是为了接受shared_ptr,如果你的对象没有internal_weak_this来确保它没有被破坏,那么你的形状会非常糟糕。

答案 6 :(得分:0)

您需要在整个层次结构的每种类型中使用静态工厂函数。

class Foo
{
public:
    static shared_ptr< Foo > instantiate( /* potential arguments */ )
    {
           return shared_ptr< Foo >( new Foo( /* potential arguments */ );
    }

// blah blah blah
};

class Bar : public Foo
{
public:
    static shared_ptr< Bar > instantiate( /* potential arguments */ )
    {
           return shared_ptr< Bar >( new Bar( /* potential arguments */ );
    }

// blah blah blah
};

如果您仍有任何疑惑,请在sourceforge上搜索CppCodeProvider,看看它是如何完成的。

答案 7 :(得分:0)

顺便说一句,在大型C ++框架中,隐藏编码器的“自动内存管理”是很常见的。这让他可以编写更简单,更简单的代码。例如,在Qt中你可以这样做:

QPixmap foo() {
    QPixmap pixmap(10, 10);
    return pixmap;
}

void bar() {
    QPixmap a = foo(); // no copying occurs, internal refcount incremented.
    QPixmap b = a;     // ditto.
    QPainter p(&b);
    p.drawPoint(5, 5); // data can no longer be shared, so a copy is made.
    // at this point 'a' is still unchanged!
    p.end();
}

与Qt中的许多内容一样,这模仿了Java对象模型,但它通过实现copy-on-write(它称之为implicit sharing)进一步发展。这是为了使API行为不那么令C ++编码人员感到惊讶,他们不习惯不得不拨打clone()

这是通过d-pointer idiom实现的,它可以同时杀死两只鸟 - 您提供自动内存管理,将您的实施与用户隔离开来(pimpl

您可以在此处查看QPixmap的实际实施:qpixmap.cppqpixmap.h