这被认为是向上倾斜吗?
Derived d = new Derived();
Base b = d; // Always OK.
为什么会有人上传?什么时候?是因为我们必须将对象转换为基类,因此它没有派生类的功能吗?
此代码在内存中的外观如何?派生类实例化并为该对象创建内存。然后创建一个基类对象,现在引用d
。
答案 0 :(得分:9)
我想你可能会对上传的内容感到有些困惑。 upcast不会禁用派生对象的功能,也不会创建新的Base对象。相反,它只是对您所提升的对象进行更有限的视图。通过基类引用,您只能访问在Base中声明的那些方法,但如果在派生类中重写了这些方法中的任何一个,则通过基类引用调用它们仍将调用派生版本。
至于你何时想要这样做,看到人们因为没有特殊原因而被人上传的情况并不常见。毕竟,这限制了你可以对对象做的事情。但是,正如其他海报所指出的那样,在将对象传递给函数或从函数返回对象时隐式向上转换是很常见的。在这些情况下,upcast允许函数作者接受具有完成工作所需的最弱要求集的参数,或者从表现出某些行为的函数返回对象而不必显示完整类型的对象
答案 1 :(得分:3)
向上转换是正常的,因为每个Derived
都是Base
。
当你编写一个继承自A类的B类时,B就是A的子类。这意味着你可以使用B 类型的对象,你可以使用一个对象A型。
你应该阅读inheritance以及它有多强大。
答案 2 :(得分:1)
如果你想使用polymorphism
,你可以使用upcast,例如你有一个接受Base
的方法,但你喜欢用Derived
调用它:
public void DoAction(Base base)
{
// do stuff
}
DoAction(drivedItem);
DoAction(baseItem);
以上两个电话都是真的。
但是在多态性中,你不能进行向下转换,你可以使用例如方法重载来克服你的问题。
答案 3 :(得分:1)
是否导致我们必须将对象转换为基类,因此它不具有派生类的功能?
因为有些代码无论您的对象是Derived1
还是Derived2
都能正常工作,并且只是基于它支持Base
功能的假设而编写。这称为抽象,将导致代码重用。您不必分别为Derived1
和Derived2
重写该功能。您抽象出特定于Derived1
和Derived2
的详细信息。
顺便说一下,很多时候,你没有明确地进行演员表演。将实例传递给函数时,只需利用这一事实即可。例如,当您向string
添加ArrayList
时,您隐式将其强制转换为基类型object
,因为Add
的签名是:
void Add(object o);
答案 4 :(得分:0)
我不确定你经常编写类似你的例子的代码,但是这种类型的转换的一个应用是方法调用:
void Test()
{
Derived d = new Derived();
this.DoSomething(d);
}
void DoSomething(Base b)
{
// something
}
在这种情况下,d
不会“变成”Base
对象,它只是被视为一个对象。我不确定,但我想与d
对象相关的实际内存根本没有变化。
答案 5 :(得分:0)
关于你的第二个问题(它们在内存中的外观),它们在堆栈上看起来都是一样的。在堆栈上,它们都是堆的简单指针。
答案 6 :(得分:0)
Reason One :如果我在2008年编写了一个知道Base
类的代码,并使用它来做一些只涉及该类功能的代码,那么upcasting可以让你创建{ 2011年的{1}}类,并将实例传递给我的代码而不做任何更改。
可以说,如果我首先使用泛型编写代码,这也可以完成(也许更强大)。
原因二:如果需要在单个容器中存储多个不同类的实例,则需要将这些实例向上转换为共享基类。例如,考虑一个“当前加载”数据源的列表,这些数据源可以是本地文件,URL,内存数据甚至套接字 - 所有这些都是共享公共数据源类的特定类。