使用C ++“虚拟构造器”一般被认为是好习惯吗?

时间:2010-05-21 19:03:27

标签: c++

是的,我知道短语“虚拟构造函数”没有意义,但我仍然看到这样的文章

一:http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=184

我听说它是​​一个c ++访谈。

普遍的共识是什么? 是“虚拟构造函数”的良好实践还是应该完全避免的事情?

更准确地说,有些人可以为我提供一个真实世界的场景,他们不得不使用它,从这里我站在这个virt的概念。构造。是一个有点无用的发明,但我可能是错的。


5 个答案:

答案 0 :(得分:1)

作者所做的全部是实现原型设计和克隆。这两者都是模式库中的强大工具。

通过使用句柄/正文习语,您实际上可以更接近“虚拟构造函数”:



struct object
{
  void f();
  // other NVI functions...
  object(...?);
  object(object const&)
  object& operator = (object const&);
  ~object();

private:
  struct impl;
  impl * pimpl;
};

struct object::impl
{
  virtual void f() = 0;
  virtual impl* clone() = 0;
  // etc...
};

struct impA : object::impl { ... };
struct impB : object::impl { ... };

object::object(...?) : pimpl(select_impl(...?)) {}
object::object(object const& other) : pimpl(other.pimpl->clone()) {}

// etc...

不知道是否有人宣称这是成语,但我发现它很有用,我相信其他人自己也会遇到同样的想法。

编辑: 当您需要请求接口的实现并且不希望将调用站点耦合到抽象后面的继承树时,可以使用工厂方法或类。

您使用原型设计(clone())来提供抽象的通用复制,这样您就不必确定类型以进行复制。

你会使用我刚刚展示的东西,原因有几个:

1)您希望完全封装抽象背后的继承关系。这是这样做的一种方法。

2)你想在抽象级别将它视为一种值类型(你将被迫使用指针或其他东西)

3)您最初有一个实现,并且想要添加新规范而无需更改客户端代码,这些代码都是在自动声明或名称堆分配中使用原始名称。

答案 1 :(得分:1)

编写“虚拟构造函数”的最佳方法是使用带有Clone()虚方法的Prototype模式,该方法调用对象的实际类型的复制构造函数,并返回指向基类的指针。


class Base
{
public:
    virtual Base*    Clone() { return new Base(*this); }
};

class Derived : public Base
{
    virtual Base*    Clone() { return new Derived(*this); }
};

这不是一个好习惯,只有在你需要时才使用(例如实现复制粘贴功能)

答案 2 :(得分:1)

当使用而不是构造函数时,我认为这些所谓的“虚拟构造函数”是糟糕的设计。这些只是虚拟函数,应该在使用类实例的开始时调用。

从您发布的链接:

class Browser
{
public:
  //virtual default constructor
  virtual Browser* construct() {return new Browser;} 
};

让我们添加一个成员字段:

class Browser
{
  int member;
public:
  //virtual default constructor
  virtual Browser* construct() {return new Browser;} 
};

我们需要初始化成员字段,我们该怎么做?

class Browser
{
  int member;
public:
  //virtual default constructor
  virtual Browser* construct() 
  { 
    Browser* b = new Browser;
    b->member = 0;
    return b;
  } 
};

考虑某人忘记使用template <class T> void func(T & obj)并执行以下操作的情况:

Browser b;
printf("member=%d", b.member);

这样就可以使用未初始化的字段。没有办法阻止它。

现在,在这种情况下

class Browser
{
  int member;
public:
  Browser() : member(0) { }
  virtual Browser* construct() { /* some init stuff */ return new Browser;} 
};

始终使用默认构造函数,并始终初始化成员字段。 但是,如果将construct()称为“虚拟构造函数”,我会考虑使用命名滥用。

我上面展示的模式很常见,例如。在MFC。 CWnd和类似的类使用构造函数来初始化实例和Create(...)函数来完全初始化和创建控件。无论如何,我绝不会将Create(...)函数称为“虚拟构造函数”。

答案 3 :(得分:0)

这是你可以使用的东西,但只有当你真的,真的需要它。即使是链接中的人也说如果绝望的话,你只能使用它。

答案 4 :(得分:0)

以上所有答案都没有回答这个问题,但正在给出一些解决方法。上述问题的答案是http://www.stroustrup.com/bs_faq2.html#virtual-ctor直接来自语言作者本身。简而言之,它表示你需要完整的信息来构造一个对象,因此在C ++中不存在虚构造函数。