如何从另一个继承的方法中覆盖继承的方法 class
How to override an inherited method from within another inherited class
我想知道是否可以通过调用控制台应用程序或超级超级 class 来覆盖方法?我知道我可以在 DoMath 中覆盖 WriteLog....但是考虑到我想在控制台应用程序中管理它。
示例:
public class LogThings
{
public virtual void WriteLog(string value)
{
Console.WriteLine("This is the base in LogThings " + value);
}
}
class继承基础。我有点想,如果我再次添加该方法并将其标记为 new 以作为虚拟实现,那么我可以在继承 DoMath 的控制台应用程序中覆盖它吗?
public class DoMath : LogThings
{
public double DoAddition(double a, double b)
{
double result;
result = a + b;
WriteLog(result.ToString()); // < the operation I need to overload
return result;
}
public new virtual void WriteLog(string value)
{
Console.WriteLine("this is overriding the base in DoMath");
base.WriteLog(value);
}
}
一些控制台应用程序使用 doMathANDLog class 库:
class Program : DoMath
{
static void Main(string[] args)
{
var m = new DoMath();
m.DoAddition(1, 2);
Console.ReadLine();
}
public override void WriteLog(string value)
{
Console.WriteLine("this is not overriding.");
}
}
当运行时结果是这样的:
this is overriding the base in DoMath
This is the base in LogThings 3
有办法吗?
如评论中所述,DoMath
提供了 WriteLog
方法的新实现(在定义中)。然后,您的 Program
class 会覆盖该实现。
'failing' 在这里:
var m = new DoMath();
您没有使用覆盖的方法创建 Program
的实例,因此永远不会使用覆盖。请尝试 new Program()
。
这是一个既有趣又烦人的问题! :) 我相信这里缺少的 link 之一是:
override
modifier与virtual
或abstract
方法相关;带有 override
修饰符的方法只是为现有的 virtual
或 abstract
方法提供替代实现。 virtual
方法有默认实现,abstract
方法根本没有实现。
- 然而,
new
modifier 可以应用于 any 方法,并且只允许重用已经使用的 name .这些方法完全没有关系,唯一的相似之处就是强行重名了。
new
的问题是使用 new
方法的类型“假装”原始实现不存在。然而 base class 完全没有意识到这一点 - new
切断了层次结构中的 link,这就是你的问题所在。
一般来说,您不想使用 new
修饰符。
那个,您可能想改用 var m = new Program();
- 原因在下面解释。
考虑这两段代码:
LogThings a = new DoMath();
a.WriteLog("something");
和
LogThings a = new Program();
a.WriteLog("something");
此时调用的方法是LogThings.WriteLog()
。即使我们实例化一个提供 new
方法的 DoMath
或 Program
class,世界的 LogThings
部分并不“知道”那个。相反,它相信有一个 virtual
方法不会碰巧被覆盖。结果,此代码打印:
This is the base in LogThings something
如上所述:new
切断 link.
在下一个示例中,调用的方法确实是 DoMath.WriteLog()
,因为我们现在只是实例化 DoMath()
class 并调用它的 LogThings
方法。
DoMath b = new DoMath();
b.WriteLog("something");
不足为奇,此代码打印
this is overriding the base in DoMath
This is the base in LogThings something
请注意,它不会打印“这不是覆盖”,因为我们没有实例化 Program
class 的实例。同样,base.LogThings()
调用与“覆盖”无关,它只是将焦点更改为 LogThings
类型并调用它知道的任何实现。
这与您使用的原始代码相似:
var m = new DoMath();
最后,考虑这个版本:
DoMath c = new Program();
c.WriteLog("something");
这里的Program
class实际上是overrides
DoMath
的virtual void WriteLog
方法。因此,此代码打印
this is not overriding.
...现在是错误的,因为确实如此。
理解这一点的关键是每个包含虚方法或抽象方法的 class 都有所谓的虚函数 table 或 vtable。此 vtable 由派生的 classes“继承”,并允许编译器知道调用方法的哪个实现(通过所谓的虚拟分派)。
您可以将 vtable 中的条目视为指向方法实际实现的指针(来自当前 class 的那个),然后是指向以前的实现。
在您的 DoMath
和 Program
示例中,实例化 DoMath
class 将生成仅包含
的 vtable
DoMath.WriteLog(string) -> null
而实例化 Program
class 会产生这样的条目:
Program.WriteLog(string) -> DoMath.WriteLog(string) -> null
这就是 ((DoMath)new Program()).WriteLog()
起作用的原因 - 即使我们查看 DoMath
引用,编译器也会查找实例化类型的 vtable (Program
)并且可以跟随链条直到实际实施 (Program.WriteLog
)。
但是请注意其中的临时 null
。因为 DoMath
class 将 WriteLog
方法声明为 new
,它被认为是一个 - 很好的 - 新方法,与 [=36= 中的方法无关].对于LogThings
,vtable的世界看起来还是有点像这样:
LogThings.WriteLog(string) -> null
因为没有合法的 override
- 只有一个 不同的 方法恰好具有相同的名称 - ((LogThings)new Program()).WriteLog()
调用 LogThings.WriteLog()
,因为那是链中的最后一个实现。 new
本质上是“强迫”另一个 vtable,导致这种有点脑裂的设置。
请注意,对 vtable 的描述过于简单化了;然而,关于该主题有很多好的 material。
我想知道是否可以通过调用控制台应用程序或超级超级 class 来覆盖方法?我知道我可以在 DoMath 中覆盖 WriteLog....但是考虑到我想在控制台应用程序中管理它。
示例:
public class LogThings
{
public virtual void WriteLog(string value)
{
Console.WriteLine("This is the base in LogThings " + value);
}
}
class继承基础。我有点想,如果我再次添加该方法并将其标记为 new 以作为虚拟实现,那么我可以在继承 DoMath 的控制台应用程序中覆盖它吗?
public class DoMath : LogThings
{
public double DoAddition(double a, double b)
{
double result;
result = a + b;
WriteLog(result.ToString()); // < the operation I need to overload
return result;
}
public new virtual void WriteLog(string value)
{
Console.WriteLine("this is overriding the base in DoMath");
base.WriteLog(value);
}
}
一些控制台应用程序使用 doMathANDLog class 库:
class Program : DoMath
{
static void Main(string[] args)
{
var m = new DoMath();
m.DoAddition(1, 2);
Console.ReadLine();
}
public override void WriteLog(string value)
{
Console.WriteLine("this is not overriding.");
}
}
当运行时结果是这样的:
this is overriding the base in DoMath
This is the base in LogThings 3
有办法吗?
如评论中所述,DoMath
提供了 WriteLog
方法的新实现(在定义中)。然后,您的 Program
class 会覆盖该实现。
'failing' 在这里:
var m = new DoMath();
您没有使用覆盖的方法创建 Program
的实例,因此永远不会使用覆盖。请尝试 new Program()
。
这是一个既有趣又烦人的问题! :) 我相信这里缺少的 link 之一是:
override
modifier与virtual
或abstract
方法相关;带有override
修饰符的方法只是为现有的virtual
或abstract
方法提供替代实现。virtual
方法有默认实现,abstract
方法根本没有实现。- 然而,
new
modifier 可以应用于 any 方法,并且只允许重用已经使用的 name .这些方法完全没有关系,唯一的相似之处就是强行重名了。
new
的问题是使用 new
方法的类型“假装”原始实现不存在。然而 base class 完全没有意识到这一点 - new
切断了层次结构中的 link,这就是你的问题所在。
一般来说,您不想使用 new
修饰符。
那个,您可能想改用 var m = new Program();
- 原因在下面解释。
考虑这两段代码:
LogThings a = new DoMath();
a.WriteLog("something");
和
LogThings a = new Program();
a.WriteLog("something");
此时调用的方法是LogThings.WriteLog()
。即使我们实例化一个提供 new
方法的 DoMath
或 Program
class,世界的 LogThings
部分并不“知道”那个。相反,它相信有一个 virtual
方法不会碰巧被覆盖。结果,此代码打印:
This is the base in LogThings something
如上所述:new
切断 link.
在下一个示例中,调用的方法确实是 DoMath.WriteLog()
,因为我们现在只是实例化 DoMath()
class 并调用它的 LogThings
方法。
DoMath b = new DoMath();
b.WriteLog("something");
不足为奇,此代码打印
this is overriding the base in DoMath
This is the base in LogThings something
请注意,它不会打印“这不是覆盖”,因为我们没有实例化 Program
class 的实例。同样,base.LogThings()
调用与“覆盖”无关,它只是将焦点更改为 LogThings
类型并调用它知道的任何实现。
这与您使用的原始代码相似:
var m = new DoMath();
最后,考虑这个版本:
DoMath c = new Program();
c.WriteLog("something");
这里的Program
class实际上是overrides
DoMath
的virtual void WriteLog
方法。因此,此代码打印
this is not overriding.
...现在是错误的,因为确实如此。
理解这一点的关键是每个包含虚方法或抽象方法的 class 都有所谓的虚函数 table 或 vtable。此 vtable 由派生的 classes“继承”,并允许编译器知道调用方法的哪个实现(通过所谓的虚拟分派)。
您可以将 vtable 中的条目视为指向方法实际实现的指针(来自当前 class 的那个),然后是指向以前的实现。
在您的 DoMath
和 Program
示例中,实例化 DoMath
class 将生成仅包含
DoMath.WriteLog(string) -> null
而实例化 Program
class 会产生这样的条目:
Program.WriteLog(string) -> DoMath.WriteLog(string) -> null
这就是 ((DoMath)new Program()).WriteLog()
起作用的原因 - 即使我们查看 DoMath
引用,编译器也会查找实例化类型的 vtable (Program
)并且可以跟随链条直到实际实施 (Program.WriteLog
)。
但是请注意其中的临时 null
。因为 DoMath
class 将 WriteLog
方法声明为 new
,它被认为是一个 - 很好的 - 新方法,与 [=36= 中的方法无关].对于LogThings
,vtable的世界看起来还是有点像这样:
LogThings.WriteLog(string) -> null
因为没有合法的 override
- 只有一个 不同的 方法恰好具有相同的名称 - ((LogThings)new Program()).WriteLog()
调用 LogThings.WriteLog()
,因为那是链中的最后一个实现。 new
本质上是“强迫”另一个 vtable,导致这种有点脑裂的设置。
请注意,对 vtable 的描述过于简单化了;然而,关于该主题有很多好的 material。