I have a class B extends class A, and it have the toJson method override the class A's toJson method. But when i force class B to class A, the toJson method not be changed from class B to class A.
class A {
String str1;
A(this.str1);
Map<String, dynamic> toMap() => {
'str1': str1,
}
}
class B extends A {
String str2;
B(this.str2, str1) : super(str1);
Map<String, dynamic> toMap() => {
'str2': str2,
'str1': str1,
}
}
void test(A a) {
print(a.toMap());
}
// When I pass class B in class A parameter, it still use the class B.toMap method.
B b = B('str2', 'str1');
test(b);
CodePudding user response:
All Dart instance methods are virtual, also known has having dynamic dispatch. That means that when you call a.toMap()
, which toMap
implementation gets called depends on the runtime type of the object a
, not the static type of the expression a
.
So, in this case, you are calling toMap
on an instance of B
, so you use B
's toMap
.
This is a fairly common behavior in object oriented languages (dynamic dispatch is one of the hallmark features of object orientation: The object determines how to respond to the message you send it, here the request to do a "toMap" operation.)
Some object oriented languages also have non-virtual methods. Dart does not. You can either define a static method:
class A {
static Map<String, dynamic> toMap(A value) => ...;
}
class B {
static Map<String, dynamic> toMap(B value) => ...;
}
and then choose which one to call:
print(A.toMap(a));
or you can use extension methods (which are really just static methods with a nicer call syntax) because they dispatch based on the static type of the receiver:
extension AToMap on A {
Map<String, dynamic> toMap() => ...;
}
extension BToMap on B {
Map<String, dynamic> toMap() => ...;
}
and call it normally:
print(a.toMap()); // Chooses AToMap.toMap based on static type of `a`.
In most situations, if you really want to access both A.toMap
and B.toMap
on an instance of B
, you're better of renaming one of the methods to avoid the naming conflict.