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 分两个阶段构造对象:首先是由外向内,然后是由内向外。
初始化列表是由外向内执行的(从派生类到基类)。完成此操作后,对象的成员应该被初始化,该对象被认为是“构造”的,并且
this
存在。 (这就是为什么你不能在初始化列表中以有意义的方式使用 this
;它还不存在。)(从技术上讲,直接成员初始化发生在初始化列表之前,但为了简单起见,我将它们集中在一起。)
然后构造函数主体由内向外执行(从基类到派生类)。
此方法保证在执行基类构造函数体时初始化所有对象的成员,从而允许在构造函数体中进行虚拟分派。 (相比之下,C++ 完全由内而外地构造对象,并且不允许在构造函数和析构函数中进行虚拟分派。或者与 Python 相比,在 Python 中,类主要定义自己的构造顺序,并且类负责确保任何虚函数调用由构造函数执行是安全的。)
如果没有这种方法,Dart 构造函数体要么无法保证执行虚函数(Java 方法)时的安全性,要么必须禁止虚拟分派(C++ 方法)。
这种方法的一个结果是
final
变量可以通过初始化列表进行初始化,但不能通过构造函数体进行初始化:当构造函数体执行时,所有成员变量(不是 late
且不可为空)都是预期的已经初始化了。
另请参阅:
问题是您无法将
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
}