type
date
status
slug
summary
tags
category
icon
password
网址
C++ 中构造函数不能定义为虚函数:
关于C++为什么不支持虚构造函数, Bjarne Stroustrup( 本贾尼·斯特劳斯特卢普 ) 很早以前就在 C++ Style and Technique (C++ 方式和技巧) FAQ里面做过回答: A virtual call is a mechanism to get work done given partial information. In particular,"virtual" allows us to call a function knowing only an interfaces and not the exact type of the object. To create an object you need complete information. In particular, you need to know the exact type of what you want to create. Consequently, a "call to a constructor" cannot be virtual. 出处:[Stroustrup: C++ Style and Technique FAQ] 大意是说,虚函数调用只需要“部分的”信息,即只需要知道函数接口,而不需要对象的具体类型。 但是构建一个对象,却必须知道具体的类型信息。如果你调用一个虚构造函数,编译器怎么知道你想构建是继承树上的哪种类型呢?所以构造函数不能为虚。
为什么构造函数不可以是虚函数呢?
  1. 构造函数的用途:1)创建对象,2)初始化对象中的属性, 3)类型转换 。
  1. 在类中定义了虚函数就会有一个虚函数表(vftable), 对象模型中就含有一个指向虚表的指针 (__vfptr)。在定义对象时构造函数设置虚表指针指向虚函数表。
  1. 使用指针和引用调用虚函数,在编译只需要知道函数接口,运行时指向具体对象,才能关联具体对 象的虚方法(通过虚函数指针查虚函数表得到具体对象中的虚方法)
  1. 构造函数是类的一个特殊的成员函数: 1)定义对象由系统自动调用构造函数,对象自己是不可以调用构造函数; 2)构造函数的调用属于静态联编,在编译时必须知道具体的类型信息。
  1. 如果构造函数可以定义为虚构造函数, 使用指针调用虚构造函数, 如果编译器采用静态联编,构 造函数就不能为虚函数。如果采用动态联编,运行时指针指向具体对象,使用指针调用构造函数, 相当于已经实例化的对象在调用构造函数,这是不容许的调用, 对象的构造函数只执行一次 。
  1. 如果指针可以调用虚构造函数, 通过查虚函数表,调动虚构造函数,那么,当指针为nullptr, 如何 查虚函数表呢?
  1. 构造函数的调用是在编译时确定,如果是虚构造函数,编译器怎么知道你想构建是继承树上的哪种类型呢?
总结:构造函数不允许是虚函数。
Bjarne建议的解决方案是factory pattern,也就是为每一个要构建的类型再创建一个对应的 factory,把问题放到factory的make方法中去解决。这也是C++中的通用解决方案。 虚析构函数: 析构函数是类的一个特殊的成员函数: 1)当一个对象的生命周期结束时,系统会自动调用析构函数注销该对象并进行善后工作,对象自身 也可以调用析构函数; 2)析构函数的善后工作是:释放对象在生命期内获得的资源(如动态分配的内存,内核资源); 3)析构函数也用来执行对象即将被撤销之前的任何操作。 根据赋值兼容规则,可以用基类的指针指向派生类对象,如果使用基类型指针指向动态创建的派生 类对象,由该基类指针撤销派生类对象,则必须将析构函数定义为虚函数,实现多态性,自动调用派生 类析构函数,否则可能存在内存泄漏问题。
总结: 在实现运行时的多态,无论其他程序员怎样调用析构函数都必须保证不出错,所以必须把析构函数定义为虚函数。
注意:类中没有虚函数,就不要把析构函数定义为虚。 在动态分配内存时所有C++的标准库函数都采用这种格式。