我想知道是否可以通過呼叫控制臺應用程式或超級超類來覆寫方法?我知道我可以在 DoMath 覆寫 WriteLog ......但是考慮到我想在控制臺應用程式中管理它。
例子:
public class LogThings
{
public virtual void WriteLog(string value)
{
Console.WriteLine("This is the base in LogThings " value);
}
}
繼承基類的類。我有點想,如果我再次添加該方法并將其標記為 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 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.");
}
}
運行時結果是這樣的:
這是覆寫 DoMath
中的基礎 這是 LogThings 3 中的基礎
有沒有辦法做到這一點?
uj5u.com熱心網友回復:
如評論中所述,DoMath提供了該WriteLog方法的新實作(在定義中)。Program然后您的類會覆寫該實作。
“失敗”的地方在這里:
var m = new DoMath();
您沒有Program使用其覆寫的方法創建實體,因此永遠不會使用覆寫。試試吧new Program()。
uj5u.com熱心網友回復:
這是一個既有趣又煩人的問題!:) 我相信這里缺少的鏈接之一是:
- 該
override改性劑是有關virtual或abstract方法; 帶有override修飾符的方法只是為現有的virtualorabstract方法提供替代實作。一個virtual方法有一個默認實作,一個abstract方法根本沒有實作。 - 然而,
new修飾符可以應用于任何方法,并且只允許重用已經使用的名稱。這些方法之間根本沒有任何關系,唯一的相似之處是它們強行使用了相同的名稱。
問題new在于使用new方法的型別“假裝”原始實作從未存在。然而,基類完全不知道這一點 -new切斷層次結構中的鏈接,這就是你的問題所在。
一般來說,您不想使用new修飾符。
那,你可能想var m = new Program();改用 - 原因在下面解釋。
考慮以下兩段代碼:
LogThings a = new DoMath();
a.WriteLog("something");
和
LogThings a = new Program();
a.WriteLog("something");
此時,被呼叫的方法是LogThings.WriteLog()。即使我們實體化了提供方法的DoMathorProgram類,世界new的LogThings一部分也不“知道”這一點。相反,它相信有一個virtual不會被覆寫的方法。結果,此代碼列印:
這是 LogThings 的基礎
如上所述:new切斷該鏈接。
在下一個例子中,被呼叫的方法確實是DoMath.WriteLog(),因為我們現在只是實體化這個DoMath()類并呼叫它的LogThings方法。
DoMath b = new DoMath();
b.WriteLog("something");
毫不奇怪,此代碼列印
這是覆寫 DoMath 中的基礎
這是 LogThings 的基礎
請注意,它不會列印“這不是覆寫”,因為我們沒有實體化Program類的實體。同樣,base.LogThings()呼叫與“覆寫”無關,它只是將焦點更改為LogThings型別并呼叫它知道的任何實作。
這類似于您使用的原始代碼:
var m = new DoMath();
最后,考慮這個版本:
DoMath c = new Program();
c.WriteLog("something");
在這里,Program類實際上overrides的virtual void WriteLog方法DoMath。因此,此代碼列印
這不是壓倒一切的。
......現在是錯誤的,因為它確實如此。
The key to understanding this is that each class containing virtual or abstract methods has what's called a virtual function table, or vtable. This vtable is "inherited" by derived classes and allows the compiler to know which implementation of a method to call (through a so-called virtual dispatch).
You can consider an entry in the vtable to be something like a pointer to the actual implementation of a method (the one from the current class), followed by a pointer to the previous implementation.
In your example of DoMath and Program, instantiating the DoMath class would produce a vtable consisting of only
DoMath.WriteLog(string) -> null
whereas instantiating the Program class would produce an entry like this:
Program.WriteLog(string) -> DoMath.WriteLog(string) -> null
This is why ((DoMath)new Program()).WriteLog() works - even though we look at a DoMath reference, the compiler looks up the vtable for the instantiated type (Program) and can follow the chain up to the actual implementation (Program.WriteLog).
Do however note the makeshift null in there. Because the DoMath class declares the WriteLog method as new, it is considered to be a - well - new method, which is unrelated to the one from LogThings. For LogThings, the vtable world still looks somewhat like this:
LogThings.WriteLog(string) -> null
Because there is no legit override - just a different method that happens to have the same name - ((LogThings)new Program()).WriteLog() calls LogThings.WriteLog(), as that's the last implementation in the chain. The new essentially "forces in" another vtable, resulting in this somewhat split-brained setup.
Please note that this description of a vtable is drastically oversimplified; there's plenty of good material out there on that topic however.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/314603.html
上一篇:使類開放,但內部
