C ++在构造函数中调用最终的虚函数

时间:2018-11-25 21:40:20

标签: c++ inheritance constructor virtual-functions

的确,在构造函数和析构函数中调用虚函数不是一个好习惯,应该避免。这是因为虚函数受子类影响,但是在构造或销毁阶段中,子类尚未构造(在构造中)或已经被销毁(在破坏中)。

但是,如果在构造函数或析构函数中调用虚拟 final 函数会发生什么情况?我认为应该没有问题,因为从逻辑上讲这不是错误的。

禁止在构造函数和析构函数中调用虚拟函数,因为在子类中声明的虚拟函数的重写版本中可能会发生对子类变量(尚未初始化)的访问。

虽然虚拟final函数不是,但它是final,因此无法访问子类的变量。

但这是我的假设,并且可能还有更多原因导致在构造函数或析构函数中调用虚拟函数不合理。

因此,总而言之,

  • C ++标准中允许在构造/销毁阶段调用虚拟 final 函数吗?
  • 如果是这样,它是否已广泛应用于大多数C ++编译器?
  • 如果不是,那有什么原因吗?

2 个答案:

答案 0 :(得分:1)

  

在构造/破坏阶段调用虚拟最终函数是   是否在C ++标准中允许?

在构造/销毁过程中调用虚拟函数定义明确,并且完全合法,除非是纯虚拟函数

  

禁止在构造函数和析构函数中调用虚拟函数

我不知道(也不在乎)是谁说从样式角度,代码维护角度来看是“不好”或“禁止” ...维护代码的能力首先取决于了解相关语言并工具好;不知道在这些阶段(*)期间进行的虚拟调用会导致维护者的误解,这是通过选择经验丰富的维护者而不是笨拙的编程风格来解决的。

(*)从技术上讲不是对象“生存期”的一部分,它甚至不是一个非常有用的概念,因为对象在任何不平凡的情况下都可以使用并在其构造函数中使用(在生命周期开始之前)程序(我认为该标准应该简单地抑制这种不必要的概念)。

  

访问子类的变量(尚未初始化)可能发生在   虚拟函数的覆盖版本,该版本在   子类。

不能。在构造基类子对象B时(由构造函数B::B()说),正在构造对象的类型根据定义B

  

虚拟函数的覆盖版本,该版本在   子类。

不,当时没有子类对象,因此没有覆盖。

  

虽然虚拟final函数不是,但它是final,并且没有办法   访问子类的变量。

没关系。

多态对象的动态类型是由构造函数在基类的构造函数之后,在构造成员之前建立的。

  

如果是这样,是否可以在大多数C ++编译器中广泛实现?

在实践中,所有编译器都通过更改一个或多个vtable指针以指向该类型的适当vtable来实现设置对象的动态类型。这是施工的一部分。

这意味着在构造过程中,vptr值会随着构造派生对象而改变。

答案 1 :(得分:0)

OP 提出了一个以广泛接受的编程实践为前提的完全有效的问题。令人难过的是,他在回复中遭到了反对和嘲笑。

首先,规则是:“不要直接或间接地从构造函数或析构函数调用虚函数,试图调用正在构造或销毁的对象。”那不是意见。这就是 SEI CERT 编码标准。原始文件位于:

https://resources.sei.cmu.edu/downloads/secure-coding/assets/sei-cert-cpp-coding-standard-2016-v01.pdf

以及指向相关规则 OOP50-CPP 的链接:

https://wiki.sei.cmu.edu/confluence/display/cplusplus/OOP50-CPP.+Do+not+invoke+virtual+functions+from+constructors+or+destructors

在回答原始问题时,此规则有几个例外。其中之一,OOP50-CPP-EX2,是函数或类是否被标记为 final。然后它不能被派生类覆盖。您还可以明确限定函数调用。

是的,final 已被广泛实施。

相关问题