为什么这个泛型方法调用基类方法,而不是派生类方法
本文关键字:类方法 派生 基类 泛型方法 调用 为什么 | 更新日期: 2023-09-27 18:16:09
对于以下代码:
class B
{
public String G() { return "B.G()"; }
}
class D : B
{
public String G() { return "D.G()"; }
}
class TestCompile
{
private static String TestG<T>(T b) where T: B
{
return b.G();
}
static void Main(string[] args)
{
TestG(new D());
}
}
结果是B.G()
,而类似的c++代码的结果将是D.G()
。
为什么会有这样的区别?
使用覆盖关键字:
class B
{
public virtual String G() { return "B.G()"; }
}
class D : B
{
public override String G() { return "D.G()"; }
}
如果没有override关键字,继承的方法不会替换基方法。
没有覆盖:D obj = new D();
obj.G(); // "D.G()"
((B)obj).G(); // "B.G()"
与覆盖:D obj = new D();
obj.G(); // "D.G()"
((B)obj).G(); // "D.G()"
c#泛型只编译一次:在编译泛型的时候。(想想看:c#让你不用看到List<T>
的实现就可以使用它。)这里,从where T: B
子句中看到参数是B
,所以调用B.G
。
c++模板在每次被调用时都会被编译。当您输入TestG<D>()
时,将使用T = D
编译一个全新的TestG
副本。在调用时,编译器看到D
有自己的G
方法并调用它。
c++中与c#泛型等价的是
template<typename T>
string TestG(T t)
{
B& b = static_cast<B&>(t); // force `t` into a `B`
return b.G();
}
其他人关于使用virtual
的评论同样适用于c#和c++。
因为您忘记将B.G
标记为virtual
,将D.G
标记为override
。
你得到了这个编译器警告:
CS0108: 'D.G()'隐藏继承成员'B.G()'。如果要隐藏,请使用new关键字。
但是你选择忽略它。我对c++开发人员有更好的期望!:)
这是因为参数b
是B
类型ref.如果您将b
强制转换为D
,它将调用D
上的函数。