帮助理解C ++代码的流程执行

时间:2016-12-20 11:27:01

标签: c++ constructor initialization

我正在阅读网站 The C ++ Programming Language C++ Super-FAQ中构造函数初始化的顺序。在那里提供以下代码。

#include <iostream>
class Y {
public:
  Y();
  void f();
};
Y::Y()      { std::cout << "Initializing Y\n"; }
void Y::f() { std::cout << "Using Y\n"; }
class X {
public:
  X(Y& y);
};
X::X(Y& y) { y.f(); }
class Z {
public:
  Z();
protected:
  X x_;
  Y y_;
};
Z::Z() 
  : y_()
  , x_(y_)
{ }
int main()
{
  Z z;
  return 0;
}

此代码的打印序列为:

  

使用Y

     

初始化Y

好吧,我只是无法意识到这个打印序列是如何可能的,因为在Z类的构造函数中,Y类的实例 y _ 首先被实例化,然后实例 x _ Y :: f(),如何使用与所使用的方法顺序密切相关的打印订单怎么样?我需要实现一个Y,它可以称之为构造函数和打印例程 std :: cout&lt;&lt; “初始化Y \ n”;

2 个答案:

答案 0 :(得分:4)

X x_ Y y_ class Z x_之前Z::Z() : y_(), x_(y_) {}之后,y_定义class Z { public: Z(); protected: Y y_; X x_; }; 并首先进行初始化。将成员放置在初始化列表x_中的顺序并不重要,x_仍然是首先初始化。

由于y_的构造函数未被调用,因此某些内部元素(例如vtable)已经初始化。实际上在X&#39的构造函数中使用此对象可能会导致段错误。也许这种定义对你来说会更好。

y_

x_之后定义Y* p = 0; X x(reinterpret_cast<Y&>(p)); ,首先会调用 func showDropIn(clientTokenOrTokenizationKey: String) { let request = BTDropInRequest() let dropIn = BTDropInController(authorization: clientTokenOrTokenizationKey, request: request) { (controller, result, error) in if (error != nil) { print("ERROR") } else if (result?.cancelled == true) { print("CANCELLED") } else if result != nil { // Use the BTDropInResult properties to update your UI // result.paymentOptionType // result.paymentMethod // result.paymentIcon // result.paymentDescription } dispatch_async(dispatch_get_main_queue(), ^{ controller.dismissViewControllerAnimated(true, completion: nil) }); } dispatch_async(dispatch_get_main_queue(), ^{ self.presentViewController(dropIn!, animated: true, completion: nil) }); } ,您可以在ng2-page-scroll的构造函数中安全地使用它。

您可能希望阅读本文的Initialization order部分。

编辑: C ++值加速并信任程序员,因此它不会尝试验证给定的参数。您可以将空指针强制转换为引用,然后使用引用。

onClickkk() {
    if(this.document.location.href.indexOf('resor') !== -1 ) {
      let pageScrollInstance: PageScrollInstance = PageScrollInstance.simpleInstance(this.document, '#app-give');
      this.pageScrollService.start(pageScrollInstance);

    }
  }

这将编译,如果编译器不需要延迟我们的空指针,它将不会失败。如果您创建虚拟或尝试访问任何成员,则会导致段错误。

答案 1 :(得分:2)

您的班级Z按此顺序声明两名成员:

X x_;
Y y_;

但是,它们按相反的顺序初始化:

Z::Z()
    : y_()
    , x_(y_)
{ }

你需要小心这个,例如请参阅this questionthis

更改声明和初始化的顺序以匹配您期望的内容。你有未定义的行为,一些编译会警告你关于oder的不匹配。

您已关联的特定psot在评论中显示"// Bad: should have listed x_ before y_"并提取要点

  

注意在初始化之前使用y_(Y :: f())(Y :: Y())。