OOP 方法隐藏和重载
OOP Method hidden and overloaded
我是编程新手。我读书。有时一些例子会引发问题。求助,habr上的解释不是很清楚。
找到了一个例子 on a habr - C# 的第四个问题。
class Program
{
static void Main(string[] args)
{
var x1 = new C();
x1.Print(); //C
B x2 = new C();
x2.Print(); //C
A x3 = new C();
x3.Print(); //A
}
}
class A
{
public void Print()
{
Console.WriteLine("A");
}
}
class B : A
{
new public virtual void Print()
{
Console.WriteLine("B");
}
}
class C : B
{
override public void Print()
{
Console.WriteLine("C");
}
}
解释如下:
在第一次调用中,将显示“C”,因为对于 var,编译器将从表达式右侧推断对象的类型,这将是 C 类型。 // 一切都清楚了那.
对于第二次调用,也会显示值“C”,因为CLR 将确定对象的实际类型为C,并将调用必要的虚方法重载。 //所以...
//进一步有点看不懂
在第三种情况下,将显示“A”,因为 B.Print 方法的声明(以及它在 C 中的重载)隐藏了 A.Print 方法。因此,CLR 不会将 B.Print 和 C.Print 视为重载,而是调用一个 class 方法。
我已经在尝试逐步描述堆栈和堆上下文中发生的事情:
x2:
- 在堆上内存分配给实例 class C;
- 默认构造函数将 class C 的实例写入此部分;
- alink将这块内存写入栈中的变量x2(类型B),这是可能的,因为B是C的基数class;
- 接下来,您需要决定将调用所有 Print 方法中的哪个 Print 方法以及原因。
CLR查看变量的类型并尝试按类型调用方法,即在x2的情况下它是B.Print(),但由于我们拥有的link是一个实例classC,而对于它有重载这个方法,然后调用C.Print()方法;
x3:
- 在堆上内存分配给实例 class C;
- 默认构造函数将 class C 的实例写入此部分;
- a link将这块内存写入变量x3(类型A)在栈上,这是可能的,因为A是base class for B,B是base class 为 C;
- 接下来,您需要决定将调用所有 Print 方法中的哪个 Print 方法以及原因。
CLR查看变量的类型并尝试按类型调用方法,即在x3的情况下它是A.Print(),但由于我们的link是一个实例classC,而对于它没有重载这个方法,然后调用A.Print()方法。
1) 我的描述是真的吗?如果不是,请用这个例子解释它是如何工作的。
2) 您是否完全同意 Habr 上答案的解释,或者您会删除/添加/替换某些内容吗?
如classB在打印函数声明中写'new'关键字,它打破了A和C打印函数之间的继承联系。
是的,从它的工作原理和链接来看,我的解释是正确的。
运行时(不是编译器)根据 通过 变量 计算调用哪个版本的方法此 变量 . 引用的对象的真实类型 (MS Visual C# Step by Step 9ed, CHAPTER 12
使用继承)
Why is dynamic binding not working the way I expect it to in the following code?
我是编程新手。我读书。有时一些例子会引发问题。求助,habr上的解释不是很清楚。 找到了一个例子 on a habr - C# 的第四个问题。
class Program
{
static void Main(string[] args)
{
var x1 = new C();
x1.Print(); //C
B x2 = new C();
x2.Print(); //C
A x3 = new C();
x3.Print(); //A
}
}
class A
{
public void Print()
{
Console.WriteLine("A");
}
}
class B : A
{
new public virtual void Print()
{
Console.WriteLine("B");
}
}
class C : B
{
override public void Print()
{
Console.WriteLine("C");
}
}
解释如下: 在第一次调用中,将显示“C”,因为对于 var,编译器将从表达式右侧推断对象的类型,这将是 C 类型。 // 一切都清楚了那.
对于第二次调用,也会显示值“C”,因为CLR 将确定对象的实际类型为C,并将调用必要的虚方法重载。 //所以...
//进一步有点看不懂 在第三种情况下,将显示“A”,因为 B.Print 方法的声明(以及它在 C 中的重载)隐藏了 A.Print 方法。因此,CLR 不会将 B.Print 和 C.Print 视为重载,而是调用一个 class 方法。
我已经在尝试逐步描述堆栈和堆上下文中发生的事情:
x2:
- 在堆上内存分配给实例 class C;
- 默认构造函数将 class C 的实例写入此部分;
- alink将这块内存写入栈中的变量x2(类型B),这是可能的,因为B是C的基数class;
- 接下来,您需要决定将调用所有 Print 方法中的哪个 Print 方法以及原因。 CLR查看变量的类型并尝试按类型调用方法,即在x2的情况下它是B.Print(),但由于我们拥有的link是一个实例classC,而对于它有重载这个方法,然后调用C.Print()方法;
x3:
- 在堆上内存分配给实例 class C;
- 默认构造函数将 class C 的实例写入此部分;
- a link将这块内存写入变量x3(类型A)在栈上,这是可能的,因为A是base class for B,B是base class 为 C;
- 接下来,您需要决定将调用所有 Print 方法中的哪个 Print 方法以及原因。 CLR查看变量的类型并尝试按类型调用方法,即在x3的情况下它是A.Print(),但由于我们的link是一个实例classC,而对于它没有重载这个方法,然后调用A.Print()方法。
1) 我的描述是真的吗?如果不是,请用这个例子解释它是如何工作的。
2) 您是否完全同意 Habr 上答案的解释,或者您会删除/添加/替换某些内容吗?
如classB在打印函数声明中写'new'关键字,它打破了A和C打印函数之间的继承联系。
是的,从它的工作原理和链接来看,我的解释是正确的。
运行时(不是编译器)根据 通过 变量 计算调用哪个版本的方法此 变量 . 引用的对象的真实类型 (MS Visual C# Step by Step 9ed, CHAPTER 12 使用继承)
Why is dynamic binding not working the way I expect it to in the following code?