【问题标题】:Calling a Method in Constructor在构造函数中调用方法
【发布时间】:2011-06-19 20:26:54
【问题描述】:

Herb Sutter 在他的一篇http://www.gotw.ca 文章中提到,只有在构造函数执行完成时才构造对象(具有有效存在)。即以粗略的方式将控制传递到其最后一个括号之外。

现在考虑下面的代码

class A
{
  public:
  A() 
  { 
      f();
  }

  void f() 
  { 
      cout << "hello, world"; 
  }

}; 

int main()
{
   A a;
}

现在根据 Herb 的说法,我们不能说因为 A 没有在其构造函数中完全构造,因此在构造函数中调用 f() 是无效的,因为“this”ptr 还没有准备好。

在构造函数中确实有一个有效的“this”并且 f() 确实被调用了。

我不认为 Herb 说了什么不正确的东西……但我猜我的解释不正确……有人可以向我解释一下这到底是什么吗?

这里是文章的链接:http://www.gotw.ca/gotw/066.htm 它讨论了构造函数的异常。具体来说,这是我的问题所依据的摘录:

-对象的生命周期从什么时候开始? 当其构造函数成功完成并正常返回时。也就是说,控制到达构造函数体的末尾或更早的 return 语句。

-对象的生命周期何时结束? 当它的析构函数开始时。也就是说,控制到达析构函数体的开头。 这里的重点是对象在其生命周期开始之前的状态与其生命周期结束之后的状态完全相同——没有对象,句号。这一观察将我们带到了关键问题:

我们可以将 C++ 构造函数模型总结如下:

Either:

(a) The constructor returns normally by reaching its end or a return statement, and the object exists.

Or:

(b) The constructor exits by emitting an exception, and the object not only does not now exist, but never existed.

【问题讨论】:

    标签: c++ object constructor


    【解决方案1】:

    现在从 Herb 所说的,我们不能说 因为 A 不完全 在其构造函数内部构造 在构造函数中调用 f() 是 无效,因为“this”ptr 尚未准备好 还没有。

    只有当f()class A 或其继承层次结构的virtual 方法并且您期望f() 的运行时解析根据正确的对象时。简单来说,如果在构造函数中调用该方法,virtual 机制就不会启动。

    如果f() 不是一个虚函数,只要你知道f() 的作用,从构造函数调用它并没有什么坏处。程序员通常从构造函数调用类方法,如initialize()

    你能给我 Herb Sutter 文章的链接吗?

    【讨论】:

    • 你假设 OP 没有仔细阅读这篇文章。不看这篇文章,你不知道它是否很好地解释了情况,如果有的话。
    • @sgreeve:如果他问这个问题,这是否意味着他没有“仔细”阅读这篇文章,因为他似乎不知道 Herb Sutter 可能实际上 i> 说过吗?不,那不是马匹;这只是告诉他应该再读一遍这篇文章的另一种方式。
    • 恐怕不会,不会。我敢肯定你的意思并不是要听起来苛刻或居高临下——但在我看来,这有点。
    【解决方案2】:

    当程序流进入你的构造函数时,对象的内存已经分配,​​this 指针确实有效。

    Herb 的意思是,对象的状态可能还没有完全初始化。特别是,如果您正在构造一个派生自A 的类,那么当您仍在 A 的构造函数中时,将不会调用该类的构造函数。

    如果你有虚成员函数,这一点很重要,因为如果从 A 的构造函数中调用,派生类中的任何虚函数都不会运行。

    【讨论】:

      【解决方案3】:

      注意:准确的文章会更容易,所以我们可以有一些上下文

      生命周期的考虑实际上相当复杂。

      考虑一个对象的构造函数,有两种不同的观点:

      • 外部:即对象的用户
      • internal:即你在编写构造函数和析构函数时(特别是)

      从外部来看,一个对象的生命周期:

      • 在构造函数成功完成后开始
      • 在析构函数开始运行时结束

      这意味着如果您尝试在构建或破坏过程中访问一个对象Bad Things Happen (tm)。这主要与多线程程序相关,但如果您将指向对象的指针传递给基类,则可能会发生......这会导致......

      ...内部观点。它更复杂。您可以确定的一件事是已分配所需的内存,但部分对象可能尚未完全初始化(毕竟,您正在构建它)。

      • 在构造函数体中,可以使用类的属性和基类(已初始化),正常调用函数(应避免虚调用)。
      • 如果是基类,派生对象尚未初始化(因此对虚拟调用有限制)

      【讨论】:

        【解决方案4】:

        生命周期还没有开始的含义主要是,如果构造函数抛出异常,析构函数将不会运行。

        【讨论】:

          【解决方案5】:

          注意尚未初始化的成员变量。当心虚函数:如果函数是虚函数并且创建了派生对象,则调用的函数可能不是您期望的函数。除此之外,我没有看到从构造函数调用方法有任何问题。尤其是对象的内存已经分配好了。

          【讨论】:

            猜你喜欢
            • 2013-08-10
            • 2018-08-20
            • 2014-02-17
            • 2014-05-27
            • 2015-12-24
            相关资源
            最近更新 更多