12 c# oop polymorphism inheritance
我现在正在研究继承和多态,我遇到了编译器将评估(使用反射?)在基类型引用中存储什么类型的对象的概念,以便决定在调用方法时运行什么方法有一个覆盖.
例如:
class Shape
{
public virtual void Draw()
{
Console.WriteLine("Drawing shape...");
}
}
class Circle : Shape
{
public override void Draw()
{
Console.WriteLine("Drawing circle...");
}
}
static void Main()
{
Shape theShape = new Circle();
theShape.Draw();
}
Run Code Online (Sandbox Code Playgroud)
将输出以下内容:
Drawing circle...
Run Code Online (Sandbox Code Playgroud)
我一直认为,在声明任何类型的对象时,它是一种为特定类型的对象指定内存的方式.所以Int32 i = 2l;
这意味着我现在把内存放在一边作为整数的"占位符".但是在上面的代码中我把内存放在了一个Shape上,但它可以实际引用/存储Circle类型的对象!
cod*_*ing 20
C#(和Java)中的所有类变量实际上只是引用 - 与所谓的基本类型(例如int,float)和结构相反; Circle
写入时保留对象的实际空间new Circle()
,Shape theShape
仅保留参考空间!
任何引用变量都可以包含对所有派生类型的引用; 调用哪个方法(如果声明的话virtual
)的实际解析是通过在运行时使用虚方法表(而不是通过反射)来实现的.
解释什么是多态可以用于(引用维基百科):
[It]允许使用统一接口处理不同数据类型的值.
在您的情况下,Shape对象的公共接口将是Draw()
方法.有一个Shapes列表,并Draw()
在每个Shapes上调用方法来显示它们是完全合理的.这意味着,为了查看所有形状,您的程序不需要注意在此列表中存储哪些形状 - Draw()
将自动调用所有正确的方法.
每个类变量自动成为引用是C#(和Java)与C++等语言的巨大差异之一,您可以在其中决定变量的生存位置; 要使Circle具有值类型(在C++中),您需要编写:
Circle circle;
Run Code Online (Sandbox Code Playgroud)
如果你想要指向它,你就会写
Circle * circle = new Circle();
Run Code Online (Sandbox Code Playgroud)
Java和C#没有明确的符号使变量成为"指针"或"引用" - 只是每个应该保存对象的变量都是指针/引用!
还要注意(例如在C++中)如果使用指针或引用,则只能使用多态性; 那是因为价值类型可以像被宣布的那样被访问,而不是更多; 使用引用和指针,当你的实际变量只引用/指向某个东西时,它可以指向许多东西(无论编译器允许它指向什么).
Eri*_*ert 17
我现在正在研究继承和多态,我遇到了编译器将评估(使用反射?)在基类型引用中存储什么类型的对象的概念,以便决定在调用方法时运行什么方法有一个覆盖.
该编译器确实没有这样的评价; 编译器在代码运行之前很久就完成了.在运行时评估什么对象的类型,以决定要调用哪个虚拟方法称作.使用Reflection不会这样做.
编译器评估的是在运行时调用方法时应使用的虚方法槽.编译器发出说明"运行时,运行此代码时,在此插槽上询问此对象,并查看该插槽中存储的方法,并执行它"的指令.
如果C#没有内置它们,那么了解如何在C#中实现虚拟方法是很有教育意义的.请参阅我的三篇系列文章.
我一直认为,在声明任何类型的对象时,它是一种为特定类型的对象指定内存的方式.
现在是你的教育中开始正确使用"声明","对象"等词语的好时机.对象未声明.类型已声明.变量已声明.
因此,您的理解是,声明给定类型的局部变量是为特定类型的对象指定内存的一种方式.这几乎是正确的.如果类型是值类型,那么这是正确的.如果类型是引用类型,则该类型的局部变量是包含对实际包含该对象的其他存储的引用的存储.
这对C#来说绝对是基础,所以请确保你明白这一点.string类型的局部变量不包含字符串.它包含对字符串的引用 ; 字符串完全在其他地方,引用指的是该位置.
在上面的代码中,我将内存放在一个Shape上,但它实际上可以引用/存储Circle类型的对象!?
它可以存储对Circle 的引用,是的,因为Circle是一种Shape,因此可以在需要引用Shape的地方使用Circle.它不能存储圆,因为圆不是对Shape的引用.
如果您的笔记本包含朋友的地址,则可能包含对公寓楼内单元的引用,并且可能包含对房屋的引用.笔记本不包含公寓楼或房屋.公寓和房屋都是各种住宅; 您的笔记本包含对住宅的参考.
假设一个朋友买了一块土地,盖房子,然后发给你新的地址.您不需要在笔记本中为房子分配空间.城市区划部门已经为在其他地方建造的房屋分配了空间.您需要在笔记本中为占用地址分配空间.房子是一种住宅这一事实使得将地址放入笔记本中是合法的.
当您创建作为引用类型实例的对象时,运行时是分区部门 - 它负责为实际对象分配存储.构造函数"构建房屋".分配局部变量以存储对实际对象的存储的引用.
值类型没有引用语义; 相反,值类型的变量包含实际对象.这就是为什么值类型被称为"值类型",而引用类型被称为"引用类型"; 因为值类型的变量存储实际对象,而引用类型的变量存储对完全位于其他位置的对象的引用.
我不确定这会回答你的问题,因为你似乎没有在你的问题中提出问题.你的问题是什么?
class Contact {
public string FirstName;
public string LastName;
}
class Customer : Contact {
public int OrderNumber;
}
Run Code Online (Sandbox Code Playgroud)
当一个期望引用Contact的方法实际上被赋予对Customer的引用时,它仍然有效,因为Customer引用也是对Contact的引用.
归档时间: |
|
查看次数: |
1521 次 |
最近记录: |