如果我有一个界面
public interface IPeelable
{
void PeelMe();
}
以下继承树:
public class Fruit : IPeelable
{
public virtual void EatMe()
{
Console.WriteLine("I'm a fruit and I've been eaten");
}
public void PeelMe()
{
Console.WriteLine("I'm a fruit and I've been peeled");
}
}
public class Banana : Fruit
{
public override void EatMe()
{
Console.WriteLine("I'm a banana and I've been eaten");
}
public new void PeelMe()
{
Console.WriteLine("I'm a banana and I've been peeled");
}
}
我故意使用 new 关键字而不是虚拟/覆盖,因此Banana中的 PeelMe 方法隐藏了Fruit中的那个。
我在解释为什么打电话时遇到了问题:
IPeelable banana = new Banana();
banana.PeelMe();// returns I'm a fruit and I've been peeled
在运行时有一个隐式的upcast。
基于继承范例调用的方法:
Banana不是一个IPeelable并且每次都在Banana中调用PeelMe方法吗? 有人能解释一下幕后发生的事情吗?
答案 0 :(得分:1)
您看到的行为是因为您隐藏方法而不是覆盖它。覆盖方法会保留相同的签名,但会更改实现。隐藏方法会创建全新的方法,而不会出现任何多态行为。
请考虑以下代码:
Banana banana = new Banana();
banana.EatMe();
Fruit bananaAsFruit = banana;
bananaAsFruit.EatMe();
正如您所料,这两次都会打印I'm a banana and I've been eaten
。由于在EatMe
中使用virtual
关键字声明了Fruit
并在Banana
中覆盖了Banana
,因此.NET使用对象类型来确定要调用的方法,无论保持对它的引用的变量。无论Banana banana = new Banana();
banana.PeelMe();
Fruit bananaAsFruit = banana;
bananaAsFruit.PeelMe();
对象如何存储,都会调用相同的方法。
现在考虑调用非虚拟方法的类似代码段。这输出是什么?
banana
尽管bananaAsFruit
和Banana
都包含virtual
的相同实例,但这两个调用会产生不同的结果!那是因为没有Fruit.PeelMe
关键字,Banana.PeelMe
和Banana
方法之间没有联系 - 从编译器的角度来看,它们可能也有完全不同的名称。
在IPeelable
引用变量中存储Banana
可能会产生两种效果之一,具体取决于两种类型之间的关系。
如果Fruit
继承自IPeelable
而IPeelable.PeelMe
实施Banana.PeelMe
,Fruit
与PeelMe
之间就没有联系。 IPeelable
为Banana.PeelMe
接口实现Fruit.PeelMe
方法,并且(从编译器的角度来看)Banana
方法与IPeelable
完全不同。
如果声明Banana.PeelMe
实现IPeelable
,那么Banana
将成为IPeelable
接口的实现方法。存储在I'm a banana
参考中的EatMe
将打印virtual
。
对于override
方法,运行时只查看实际对象的类型以确定要调用的内容 - 指向它的引用类型没有区别!这就是Data := Clipboard
Xl := ComObjCreate("Excel.Application")
Xl := ComObjActive("Excel.Application")
filepath = %A_WorkingDir%\new.xlsx
Xl.Workbooks.Open(filepath)
Xl.Visible := True
Clipboard := Data
; tried these get COM error mentioned above ;
Xl.Selection.PasteSpecial(-4163)
Xl.Range("A:D").PasteSpecial(-4163)
Xl.Selection.Range("A:D").PasteSpecial(-4163)
Xl.Range("A:D").Selection.PasteSpecial(-4163)
Xl.Selection.PasteSpecial(-4163).Range("A:D")
Xl.Selection.Range("A:D") := XL.Selection.PasteSpecial(-4163)
Xl.ActiveSheet.Selection.PasteSpecial(-4163)
; tried these no COM error mentioned above but does not paste ;
ActiveSheet.PasteSpecial(-4163)
Selection.PasteSpecial(-4163)
ActiveSheet.Selection.PasteSpecial(-4163)
Selection.ActiveSheet.PasteSpecial(-4163)
ActiveSheet.Range("A:D").PasteSpecial(-4163)
ActiveSheet.PasteSpecial(-4163).Range("A:D")
ActiveSheet.Selection.PasteSpecial(-4163).Range("A:D")
ActiveSheet.Selection.Range("A:D").PasteSpecial(-4163)
ActiveSheet.Range("A:D").Selection.PasteSpecial(-4163)
和var number = 121;
var numbArr = [];
for(var x = 1; x <= 500; x++){
numbArr.push(x);
}
function shuffle(array) {
var m = array.length, t, i;
// While there remain elements to shuffle…
while (m) {
// Pick a remaining element…
i = Math.floor(Math.random() * m--);
// And swap it with the current element.
t = array[m];
array[m] = array[i];
array[i] = t;
}
return array;
}
shuffle(numbArr);
for(var x = 0; x < numbArr.length; x++){
if(number == numbArr[x]){
console.log("Found number at entry " + x);
}
}
与方法隐藏的不同之处。
答案 1 :(得分:0)
这是一个有趣的问题,我认为答案也很有趣。
解释您的问题
你问:
为什么输出
我是一个水果,我被剥了皮
而不是
我是香蕉,我已经去皮了
如果您调用以下代码
IPeelable banana = new Banana();
banana.PeelMe();// returns I'm a fruit and I've been peeled
你有一个类Fruit和一个Banana类,但只有Fruit实现了IPeelable接口。因此,IPeelable将实例化Fruit类的对象。
基于此,您的问题与以下内容相同:
为什么输出
我是一个水果,我被剥了皮
如果您调用以下代码
Fruit banana = new Banana();
banana.PeelMe();// returns I'm a fruit and I've been peeled
有了这个问题,还有另外一个问题:
背后会发生什么?
我可以给出以下答案。
<强>答案强>
背后会发生什么?
如果你致电Fruit banana = new Banana();
,它将被分配给banana的内存,其中包含两种方法。方法PeelMe()来自Fruit和Banana。如果香蕉的类型是Fruit,PeelMe()使用来自Fruit的PeelMe()的引用。如果香蕉的类型是Banana,PeelMe()使用来自Banana的PeelMe()的引用。
测试,验证我的答案
将两个图像放在顶部,你可以看到,你从Fruit的属性和Banana的属性中为整数变量分配内存。
如果您想测试它,您还可以执行以下操作:
public class Fruit : IPeelable
{
public int NumberOfBananas = 10;
public virtual void EatMe()
{
Console.WriteLine("I'm a fruit and I've been eaten");
}
public void PeelMe()
{
Console.WriteLine("I'm a fruit and I've been peeled");
}
}
public class Banana : Fruit
{
public new int NumberOfBananas = 5;
public override void EatMe()
{
Console.WriteLine("I'm a banana and I've been eaten");
}
public new void PeelMe()
{
Console.WriteLine("I'm a banana and I've been peeled");
}
}
private static void Main()
{
Fruit banana = new Banana();
Console.WriteLine(banana.NumberOfBananas); // Result: 10
Banana realBanana = (Banana)banana;
Console.WriteLine(realBanana.NumberOfBananas); // Result: 5
Fruit bananaFruit = (Fruit)realBanana;
Console.WriteLine(bananaFruit.NumberOfBananas); // Result: 10
}