Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 正在使用C++&引用;“虚拟构造函数”;一般认为良好做法?_C++ - Fatal编程技术网

C++ 正在使用C++&引用;“虚拟构造函数”;一般认为良好做法?

C++ 正在使用C++&引用;“虚拟构造函数”;一般认为良好做法?,c++,C++,是的,我知道短语“虚拟构造器”毫无意义,但我仍然看到这样的文章 一: 和我听说它被称为C++面试。 普遍共识是什么? “虚拟构造器”是一种良好的做法还是完全可以避免的 更准确地说,有人能给我提供一个他们不得不使用它的真实场景吗,从我的立场来看,virt的概念。施工。这是一个有点无用的发明,但我可能错了 这是你可以使用的东西,但只有当你真的非常需要它的时候。即使是链接中的那个家伙也说,这只是你在绝望时使用的东西。这是你可以使用的东西,但只有在你真的、真的需要它的时候。甚至链接中的那个家伙也说,这只

是的,我知道短语“虚拟构造器”毫无意义,但我仍然看到这样的文章

一:

<>和我听说它被称为C++面试。

普遍共识是什么? “虚拟构造器”是一种良好的做法还是完全可以避免的

更准确地说,有人能给我提供一个他们不得不使用它的真实场景吗,从我的立场来看,virt的概念。施工。这是一个有点无用的发明,但我可能错了


这是你可以使用的东西,但只有当你真的非常需要它的时候。即使是链接中的那个家伙也说,这只是你在绝望时使用的东西。

这是你可以使用的东西,但只有在你真的、真的需要它的时候。甚至链接中的那个家伙也说,这只是你在绝望时使用的东西。

作者所做的就是实现原型和克隆。它们都是模式库中的强大工具

通过使用handle/body习惯用法,您实际上可以做一些更接近“虚拟构造函数”的事情:



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) 您最初有一个实现,希望添加新的规范而不必更改客户机代码,客户机代码在自动声明或按名称分配堆时都使用原始名称。

作者所做的就是实现原型和克隆。它们都是模式库中的强大工具

通过使用handle/body习惯用法,您实际上可以做一些更接近“虚拟构造函数”的事情:



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) 您最初有一个实现,希望添加新规范而不必更改客户机代码,客户机代码在自动声明或按名称分配堆时都使用原始名称。

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


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

class Derived : public Base
{
    virtual Base*    Clone() { return new Derived(*this); }
};
这被认为不是一种好的做法,只能在需要时使用(例如,实现复制粘贴函数)

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


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

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

这不是一个好的做法,只在需要的时候使用(例如复制粘贴函数)

,我认为这些所谓的“虚拟构造函数”是“强>坏设计< /强”,而不是使用构造函数。这些都是虚拟函数,应该在类的实例开始使用时调用

从您发布的链接:

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;
  } 
};
假设有人忘记使用
模板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;} 
};
始终使用默认构造函数,并且始终初始化成员字段。 但是调用<代码>构造()\代码>“虚拟构造函数”,我考虑命名滥用。


上面显示的模式非常常见,例如在MFC中。CWnd和类似的类使用构造函数来初始化实例,并使用
创建(…)
函数来完全初始化和创建控件。无论如何,我不会把<代码>创建(…)>代码>函数称为“虚拟构造函数”。

< P>我认为这些所谓的“虚拟构造函数”是“强>坏设计< /强”,而不是使用构造函数。这些都是虚拟函数,应该在类的实例开始使用时调用

从您发布的链接:

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;
  } 
};
假设有人忘记使用
模板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;} 
};
始终使用默认构造函数,并且始终初始化成员字段。 但是调用<代码>构造()<代码> >“虚拟构造函数”