为什么C++没有虚拟构造函数?

没有正确的解决方案

其他提示

从马的嘴:)听到它。

从Bjarne的Stroustrup的ç

++风格和技术FAQ 为什么我们不能有虚拟构造函数?

  

一个虚拟呼叫是来完成工作给定的部分的机构   信息。特别是,“虚拟”可以让我们调用一个函数   只有知道任何接口而不是确切类型的对象。至   创建你所需要的完整信息的对象。特别是,你   要知道,你要创建的确切类型。所以,   一个“调用一个构造函数”不能是虚拟的。

在FAQ条目的推移,得到的代码的方式来实现这个目的没有虚拟构造函数。

虚拟功能基本上提供多态行为。也就是说,当你与一个对象,其动态类型为比静态不同工作(编译时间)型与它被称为,它提供行为适合于实际类型的对象,而不是静态对象的类型。

现在尝试那种行为的适用于构造函数。当构造一个对象的静态类型总是相同的实际对象类型,因为:

  

要构造对象,构造需要它是创建该对象的确切类型[...]此外[...]你不能有一个指向一个构造

(比亚Stroustup(P424的C ++编程语言SE))

与 Smalltalk 或 Python 等面向对象语言不同,其中构造函数是表示类的对象的虚拟方法(这意味着您不需要 GoF 抽象工厂模式, (因为您可以传递表示类的对象而不是创建自己的类),C++ 是一种基于类的语言,并且没有表示任何语言构造的对象。该类在运行时并不作为对象存在,因此您无法对其调用虚拟方法。

这符合“你不用为不使用的东西付费”的理念,尽管我见过的每个大型 C++ 项目最终都实现了某种形式的抽象工厂或反射。

两个原因我能想到的:

技术原因

在对象只存在之后,用于构造的构造ends.In为了使用虚拟表被分派,必须有与一个指向虚拟表中的现有对象,但如何能的指针虚拟表存在如果对象还是不存在? :)

逻辑原因

当你要声明一个有点多态行为可以使用虚拟关键字。但并没有什么用的多态构造函数,在C ++的构造函数的工作是简单地把在内存中的对象数据。由于虚拟台(和多态性总称)都是关于多态行为,而在多态的数据,没有与声明一个虚拟构造没有任何意义。

我们做什么,只是没有一个构造函数: - )

struct A {
  virtual ~A() {}
  virtual A * Clone() { return new A; }
};

struct B : public A {
  virtual A * Clone() { return new B; }
};

int main() {

   A * a1 = new B;
   A * a2 = a1->Clone();    // virtual construction
   delete a2;
   delete a1;
}

撇开语义原因不谈,在构造对象之前没有 vtable,因此虚拟指定毫无用处。

概括: :C++ 标准 可以 为“虚拟构造函数”指定一种相当直观的表示法和行为,并且对于编译器来说支持并不难,但是为什么要为此进行标准更改,特别是当 功能性 已经可以使用干净地实现 create() / clone() (见下文)?它并不像管道中的许多其他语言提案那么有用。

讨论

让我们假设一个“虚拟构造函数”机制:

Base* p = new Derived(...);
Base* p2 = new p->Base();  // possible syntax???

上面的第一行构造了一个 Derived 对象,所以 *p的虚拟调度表可以合理地提供一个“虚拟构造函数”以在第二行中使用。(本页上有数十个答案说明 “该对象尚不存在,因此虚拟构建是不可能的” 不必要地短视地关注要构造的对象。)

第二行假设符号 new p->Base() 请求动态分配和默认构造另一个 Derived 目的。

笔记:

  • 编译器必须在调用构造函数之前协调内存分配 - 构造函数通常支持 自动的 (非正式地“堆栈”)分配, 静止的 (对于全局/命名空间范围和类/函数-static 对象),以及 动态的 (非正式地“堆”)当 new 用来

    • 要构造的对象的大小 p->Base() 通常在编译时无法得知,所以 动态分配是唯一有意义的方法

  • 对于动态分配它 必须 返回一个指针,以便内存可以 delete稍后。

  • 假设的符号明确列出 new 强调动态分配和指针结果类型。

编译器需要:

  • 找出有多少内存 Derived 需要,可以通过调用隐式 virtual sizeof 功能或通过 RTTI 提供此类信息
  • 称呼 operator new(size_t) 分配内存
  • 调用 Derived() 有安置 new.

或者

  • 为结合动态分配和构造的函数创建额外的 vtable 条目

因此,指定和实现虚拟构造函数似乎并不是不可克服的,但价值百万美元的问题是:它如何比使用现有的 C++ 语言功能更好......?亲自, 我认为下面的解决方案没有任何好处。


`clone()` 和 `create()`

C++ 常见问题解答记录了“虚拟构造函数”惯用语, ,包含 virtual create()clone() 默认构造或复制构造新的动态分配对象的方法:

class Shape {
  public:
    virtual ~Shape() { } // A virtual destructor
    virtual void draw() = 0; // A pure virtual function
    virtual void move() = 0;
    // ...
    virtual Shape* clone() const = 0; // Uses the copy constructor
    virtual Shape* create() const = 0; // Uses the default constructor
};
class Circle : public Shape {
  public:
    Circle* clone() const; // Covariant Return Types; see below
    Circle* create() const; // Covariant Return Types; see below
    // ...
};
Circle* Circle::clone() const { return new Circle(*this); }
Circle* Circle::create() const { return new Circle(); }

也可以更改或超载 create() 接受参数,但要匹配基类/接口的 virtual 函数签名、重写参数必须与基类重载之一完全匹配。通过这些明确的用户提供的设施,可以轻松添加日志记录、检测、更改内存分配等。

您可以找到一个例子,出于技术上的原因,为什么它不是在@stefan的回答允许。现在,一个符合逻辑的答案根据我这个问题是:

在主要使用虚拟关键字的是使多态行为时,我们不知道基类指针会指向什么类型的对象。

不过想到这是比较原始的方式,使用虚拟功能,您将需要一个指针。又是什么指针要求?一个对象来点! (考虑情况下用于程序的正确执行)

所以,我们基本上要求已经在内存的某个地方存在的对象(我们不关心内存是如何分配的,它可能是在编译时或任一运行时),以便我们的指针可以正确地指向该对象。

现在,想什么时候必须指出的类的对象被分配一些内存的那一刻的情形 - >它的构造将在该实例本身自动调用

因此,我们可以看到,我们实际上并不需要担心的构造是虚拟的,因为在任何情况下要使用一个多态行为我们的构造将已经执行使我们的对象准备使用<! / p>

尽管虚拟构造的概念不适合公因为对象类型是先决条件对象的创建,它不是完全地过度统治。

GOF的“工厂方法”设计模式利用了虚拟构造的“概念”,这是在某些设计情况handly的。

在C ++

虚拟函数是运行时多态性的实现,以及他们将做功能覆盖。一般来说,virtual关键字是用C ++使用,当你需要动态行为。当对象存在,它只会工作。而构造函数用于创建对象。构造将在创建对象的时间被调用。

所以,如果你创建构造函数virtual,按虚拟关键字定义,它应该有现有对象使用,但构造函数用于创建对象,所以这种情况绝不会存在。所以,你不应该使用构造的虚拟。

所以,如果我们试图声明虚拟构造函数编译器抛出一个错误:

  

构造不能声明虚拟

当有人问这样的问题,我想在心里想着“如果这实际上可能会发生什么?”我真的不知道这将意味着,但我想它会有事做,能够基于动态类型正在创建的对象的覆盖构造函数实现。

我看到许多与此潜在的问题。一方面,派生类不会完全在虚拟的构造函数被调用的时候构造,所以有与实施的潜在问题。

其次,将在多重继承的情况下,发生什么事?您的虚拟构造将可能多次调用,那么你就需要有专门的一些方法,其中一个是被调用。

第三,一般在建筑的时间来说,该对象不具有虚拟表完全构造时,这意味着它需要一个大的变化的语言规范以允许的事实,所述动态对象的类型将是在施工时间知道。然后这将允许基类的构造,以在构造时也许调用其他虚拟功能,具有一个不完全构造动态类类型。

最后,正如其他人所指出的那样,你可以使用静态的“创造”或“初始化”功能型,基本上做同样的事情作为一个虚拟的构造函数会做实现一种虚拟构造函数。

虚拟功能在为了调用基于对象的类型函数中使用的指向的指针,而不是指针本身的类型。但是,一个构造函数是不是“被废除”。它被称为只有一个对象被声明时一次。所以,构造不能进行在C ++中的虚拟

您应该也不你的构造函数中调用虚函数。参考: http://www.artima.com/cppsource/nevercall.html

另外,我不知道,你真的需要一个虚拟的构造函数。你可以实现多态的建设离不开它:你可以写,将根据需要的参数构造你的对象功能

一个虚拟表(虚函数表)可以具有一个或多个“虚拟函数”各自类制成。每当创建这样类的一个对象,它包含了“虚拟指针”,其指向相应的vtable的基极。每当有虚函数调用,虚函数表是用来解决该函数的地址。     构造函数不能是虚拟的,因为当执行类的构造函数没有在存储器中没有虚函数表,意味着还没有定义虚拟指针。因此,构造应该总是非虚拟

广东话简单的说像。我们不能继承构造函数。所以没有点声明它们虚拟因为虚拟提供的多态性。

当你有一个基于类指针指向一个派生类对象的虚拟机制只。建设有它自己的规则,基类构造的电话,基本上基类派生。虚拟构造怎么可能是有用的或叫什么名字?我不知道还有什么其他语言一样,但我不能看到一个虚拟的构造如何能是有用的,甚至实现。施工需要已经发生对虚拟机制任何意义和构造还需要已发生用于向已创建的虚表结构,该结构提供了多态行为的机制。

有一个非常基本的原因:构造函数是有效的静态函数,和在C ++中没有静态函数可以是虚拟的

如果你有C ++太多的经验,你知道所有关于静态的成员函数之间的差异。静态函数与类,而不是对象(实例)相关联,因此他们没有看到一个“this”指针。只有成员函数可以是虚拟的,因为vtable-函数指针,使得“虚拟”与工作是真的每个对象的数据成员的隐藏的表。

现在,什么是构造函数的工作吗?这是作为他们就分配一个“T”构造函数初始化T对象的名字 - 。这会自动排除它是一个成员函数!对象具有存在它有一个“this”指针,因此一个虚函数表之前。这意味着,即使语言处理构造函数普通函数(没有的话,对相关原因,我不会进入),他们必须是静态成员函数。

看到这一个伟大的方式是看“工厂”模式,尤其是工厂的功能。他们做你以后,你会发现,如果T类有一个工厂方法,它总是静态的。它必须是

C ++虚拟构造不是possible.For例如,你不能标记构造为virtual.Try此代码

#include<iostream.h>
using namespace std;
class aClass
{
    public:
        virtual aClass()
        {   
        }  
};
int main()
{
    aClass a; 
}

它导致error.This代码试图宣布一个构造为虚拟的。 现在让我们试着去了解为什么我们使用虚拟关键字。虚拟关键字用来提供运行时多态性。例如尝试此代码。

#include<iostream.h>
using namespace std;
class aClass
{
    public:
        aClass()
        {
            cout<<"aClass contructor\n";
        }
        ~aClass()
        {
            cout<<"aClass destructor\n";
        }

};
class anotherClass:public aClass
{

    public:
        anotherClass()
        {
            cout<<"anotherClass Constructor\n";
        }
        ~anotherClass()
        {
            cout<<"anotherClass destructor\n";
        }

};
int main()
{
    aClass* a;
    a=new anotherClass;
    delete a;   
    getchar(); 
}

在主a=new anotherClass;分配在声明为类型anotherClass.This的指针a用于aClass存储器导致两个构造函数(在aClassanotherClass)来调用automatically.So我们不需要当标记构造为virtual.Because对象被创建它必须遵循建立的链(即,第一基体,然后将派生类)。 但是,当我们试图删除它会导致调用只有基地delete a; destructor.So我们使用虚拟关键字来处理析构函数。的所以虚拟构造是不可能的,但虚拟的析构函数是 .Thanks

如果您逻辑思考如何建设者的工作和什么是虚函数的含义/用法是在C ++中,那么你会发现,一个虚拟的构造函数是没有意义的C ++。声明的东西在C ++中的虚拟意味着它可以通过一个子类当前类的覆盖,但是构造函数时,反对被调用时创建,在那个时候,你不能创建一个子类的类的,你必须是创建类所以永远不会有任何需要声明构造虚拟

和另一个原因是,该构造具有相同的名称作为它的类名,如果我们声明构造虚拟,那么它应该在具有相同名称的派生类中重新定义,但你不能有两个同名的类。因此,它不可能有一个虚拟的构造函数。

  1. 当调用构造函数时,尽管到目前为止还没有创建对象,但我们仍然知道将要创建的对象类型,因为 具体构造函数 该对象所属的类已经被调用。

    Virtual 与函数关联的关键字意味着 特定对象类型的函数 将会被召唤。

    所以,我的想法是,没有必要创建虚拟构造函数,因为要创建对象的所需构造函数已经被调用,并且使构造函数成为虚拟只是一件多余的事情,因为 对象特定的构造函数 已经被调用,这与调用相同 类特定函数 这是通过virtual关键字实现的。

    尽管由于 vptr 和 vtable 相关原因,内部实现不允许使用虚拟构造函数。


  1. 另一个原因是C++是静态类型语言,我们需要在编译时知道变量的类型。

    编译器必须知道类类型才能创建对象。要创建的对象的类型是编译时决定的。

    如果我们将构造函数设为虚拟,则意味着我们不需要在编译时知道对象的类型(这就是虚拟函数提供的)。我们不需要知道实际的对象,只需要基指针指向一个实际的对象(调用所指向对象的虚函数而不知道该对象的类型),如果我们在编译时不知道该对象的类型那么它是针对静态类型语言的。因此,无法实现运行时多态性。

    因此,在编译时不知道对象类型的情况下,不会调用构造函数。因此创建虚拟构造函数的想法失败了。

在Vpointer在创建对象时创建。 vpointer对象创建之前,不会存在。所以没有使构造为虚拟的点。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top