在参数列表和初始化列表中赋值的区别 [英] Difference between assigning the values in parameter list and initializer list

查看:18
本文介绍了在参数列表和初始化列表中赋值的区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

class A {
  A(int value);
}

class B extends A{
  final int foo;

  B.one(this.foo) : super(foo); // Works

  B.two(int foo) : foo = foo, super(this.foo); // Doesn't work
}

B.one中,我可以很容易地将foo的值传递给super,但在B.two中>,我做不到.在这两种情况下,字段 foo 在调用 super 之前被分配,在一种情况下它有效,而在另一种情况下它失败.所以,问题是在构造函数中创建字段的时间点.

In B.one, I can easily pass the value of foo to super but in B.two, I can't do that. In both cases, the field foo is assigned before calling super, in one case it works and in another it fails. So, the question is at what point the fields are created in the constructor.

推荐答案

Dart 分两个阶段构造对象:先由外向内,然后由内向外.

Dart constructs objects in two phases: first outside-in and then inside-out.

初始化器列表由外向内执行(从派生类到基类).完成后,对象的成员应该被初始化,对象被认为是构造的",并且this存在.(这就是你不能在初始化列表中以有意义的方式使用 this 的原因;它还不存在.)(技术上直接成员初始化发生在初始化列表之前,但我将它们混为一谈为简单起见.)

Initializer lists are executed outside-in (from derived class to base class). After this is done, the object's members should be initialized, the object is considered to be "constructed", and this exists. (That's why you can't use this in a meaningful way in an initializer list; it doesn't exist yet.) (Technically direct member initialization occurs before initializer lists, but I'm lumping them together for simplicity.)

然后从内到外执行构造函数体(从基类到派生类).

Constructor bodies are then executed inside-out (from base class to derived class).

这种方法保证在基类构造函数体执行时对象的所有成员都被初始化,允许在构造函数体中进行虚拟分派.(相比之下,C++ 完全由内而外地构造对象,并且不允许在构造函数和析构函数中进行虚拟分派.或者与 Java 相比,IIRC 类大多定义自己的构造顺序,类负责确保执行任何虚函数调用通过构造函数是安全的.)

This approach guarantees that all of the object's members are initialized when the base class constructor body executes, allowing virtual dispatch to occur in the constructor body. (In contrast, C++ constructs objects purely inside-out and disallows virtual dispatch in constructors and destructors. Or contrast to Java where, IIRC, the class mostly defines its own construction order, and the classes are responsible to ensure that any virtual function calls performed by the constructor are safe.)

如果没有这种方法,Dart 构造函数体要么在执行虚函数时不能保证安全(Java 方法),要么必须禁止虚拟分派(C++ 方法).

Without this approach, a Dart constructor body either cannot guarantee safety when executing virtual functions (the Java approach) or must disallow virtual dispatch (the C++ approach).

这种方法的一个结果是 final 变量可以由初始化列表初始化,但不能由构造函数体初始化:当构造函数体执行时,所有成员变量(不是 late 并且不可为空)预计已经被初始化.

One consequence of this approach is that final variables can be initialized by initializer lists but not by constructor bodies: when the constructor body executes, all member variables (that aren't late and that aren't nullable) are expected to be initialized already.

另见:

  • https://stackoverflow.com/a/64548861/ for various differences between the different ways to initialize members and for an example where the different ways matter.
  • Virtual functions in constructors, why do languages differ?

这篇关于在参数列表和初始化列表中赋值的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆