以下代码:
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()
。
为什么会出现这种差异?
答案 0 :(得分:9)
使用override关键字:
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()"
答案 1 :(得分:6)
C#泛型只编译一次:编译泛型时。 (考虑一下:C#允许你使用List<T>
而不看其实现。)在这里,它从where T: B
子句看到参数是B
,因此它调用B.G
}。
每次调用C ++模板时都会编译它们。当您键入TestG<D>()
时,TestG
的全新副本将使用T = D
进行编译。在调用时,编译器会看到D
有自己的G
方法并调用它。
C#generic的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 ++。我只是在解释为什么C ++与C#的行为不同。
答案 2 :(得分:3)
因为你忽略了将B.G
标记为virtual
,将D.G
标记为override
。
你收到了这个编译器警告:
CS0108:'D.G()'隐藏继承成员'B.G()'。如果想要隐藏,请使用new关键字。
但你选择忽略它。我希望C ++开发人员能做得更好! :)
答案 3 :(得分:0)
这是因为参数b
位于B
类型参考中。如果您将b
投射到D
,则会调用D
上的函数。