参数列表和初始化列表中赋值的区别

问题描述 投票:0回答:2
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
之前被分配,在一种情况下它有效,在另一种情况下它失败。所以,问题是在构造函数中什么时候创建字段。

dart constructor
2个回答
8
投票

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

初始化列表是由外向内执行的(从派生类到基类)。完成此操作后,对象的成员应该被初始化,该对象被认为是“构造”的,并且

this
存在。 (这就是为什么你不能在初始化列表中以有意义的方式使用
this
;它还不存在。)(从技术上讲,直接成员初始化发生在初始化列表之前,但为了简单起见,我将它们集中在一起。)

然后构造函数主体由内向外执行(从基类到派生类)。

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

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

这种方法的一个结果是

final
变量可以通过初始化列表进行初始化,但不能通过构造函数体进行初始化:当构造函数体执行时,所有成员变量(不是
late
且不可为空)都是预期的已经初始化了。

另请参阅:


1
投票

问题是您无法将

this
或其属性传递给
super

this
仅在实例方法或生成构造函数的上下文中定义。

请参阅:https://dart.dev/tools/diagnostic-messages#invalid_reference_to_this

这有效

class B extends A{
  final int foo;

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

  B.two(int foo) : foo = foo, super(foo); 
}

区别 在

B.one
中,您将传递给 super
foo
作为属性
foo
,但在
B.two
中,您从
foo
 上的参数传递 
two

看看这个;

class A {
  A(int value) {
    print(value);
  }
}

class B extends A {
  final int foo;

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

  B.two(int foo): foo = 5, super(foo);
}

main() {
 B b = B.two(100); //Prints 100;
 print(b.foo); //Prints 5
}
© www.soinside.com 2019 - 2024. All rights reserved.