我是一名.Net编码员(不能说我是程序员)已经2年了。有一个问题多年来我无法理解,那就是基类的实例如何能够保存派生类的实例呢?
假设我们有两个类:
class BaseClass
{
public A propertyA;
public B propertyB;
}
class DerivedClass :BaseClass
{
public C propertyC;
}
怎么会发生这种情况:
BaseClass obj = new DerivedClass ()
我的意思是,BaseClass
的内存模型没有空间用于新添加的propertyC,那么它怎么能保持propertyC的值?
另一方面,怎么可能不会发生这种情况:
DerivedClass obj = new BaseClass()
我认为这是正确的方法,因为DerivedClass
的内存模型具有BaseClass的所有空间甚至更多。但这不是真的,为什么?
我知道我问的是一个非常愚蠢的问题,但有人可以给我一个更详细的答案吗?从内存或编译器的角度来看会更好。
答案 0 :(得分:6)
因为(并且这个概念经常被误解),持有指针的变量与它指向的对象的实际具体类型无关。
所以当你写
BaseClass obj = new DerivedClass ()
表示BaseClass obj
的部分在堆栈上创建一个新的引用变量,编译器可以理解该引用来保存对BaseClass
的某些内容的引用。
读取= new DerivedClass ()
的部分实际上会创建一个类型为DerivedClass
的新对象,将其存储在堆中,并将指针存储到obj
指向的内存位置中的该对象。堆上的实际对象是 DerivedClass
;这被称为对象的具体类型。
变量obj
被声明为BaseClass
类型。这不是具体类型,它只是一个变量类型,它只限制编译器将地址存储到指向的变量中一个不是BaseClass
的对象,或者不是从BaseClass
类型派生的对象。
这样做是为了保证无论你输入obj变量是什么,无论它是BaseClass
还是DerivedClass
的具体类型,它都将拥有所有的方法,属性和其他成员。类型BaseClass
。它告诉编译器obj
变量的所有用法都应该仅限于使用类BaseClass
的那些成员。
答案 1 :(得分:4)
由于BaseClass
是引用类型,obj
不是BaseClass
对象。它是BaseClass
对象的引用。具体而言,它是对BaseClass
的{{1}}部分的引用。
答案 2 :(得分:2)
当你这样说时:
BaseClass obj = new DerivedClass ()
你不是说“创建一个包含这个BaseClass对象的容器,然后将这个更大的DerivedClass对象塞入其中”。
实际上,您正在创建DerivedClass对象,并且它正在足以用于DerivedClass对象的内存空间中创建。 .NET框架永远不会忘记这一事实,特别是DerivedClass,它也不会停止对它进行处理。
但是,当你说选择使用BaseClass对象变量时,你只是创建一个指向该对象的引用/指针,该对象已经被创建,分配和定义了所有这些,而你的指针只是更加模糊一点。
就像在房间另一边那边的那个人是一个红头发的爱尔兰略微超重的鸡农,牙齿不好,性格迷人,名叫吉米,但你只是把他称为“那边的那个家伙” ”。你在描述他时含糊不清的事实并没有改变他的内容或他的任何细节,即使你的模糊描述是完全准确的。
答案 3 :(得分:0)
从另一个用户jk在Stackoverflow上写一个完全相同的问题,逐字逐句复制了答案。
如果我告诉你我有一只狗,你可以放心地假设我有一只狗。
如果我告诉你我有一只宠物,你不知道那只动物是狗还是狗 可能是一只猫,甚至可能是一只长颈鹿。不知道一些额外的 你不能安全地假设我有一条狗的信息。
类似地,派生对象是基类对象(作为它的子 class),所以可以通过基类指针指向。但是一个基地 class对象不是派生类对象,因此无法分配给a 派生类指针。
(你现在听到的吱吱声是类比拉伸)
假设你现在想给我买一件宠物的礼物。
在第一个场景中,你知道它是一只狗,你可以给我买一条皮带, 每个人都很开心。
在第二种情况下,我没有告诉你我的宠物是什么,如果你是的话 无论如何你要给我买礼物你需要知道我没有的信息 告诉你(或只是猜测),你给我带了皮带,如果事实证明我真的 每个人都很开心。
然而,如果我真的有一只猫,那么我们现在知道你做了一个坏事 假设(演员)并且在皮带上有一个不快乐的猫(运行时错误)
答案 4 :(得分:0)
这是可能的,因为为基类和派生类分配了内存。在派生类中,首先分配基类的实例变量,然后是派生类的实例变量。将基类引用变量赋给派生类对象时,它会看到它所期望的基类实例变量加上" extra"派生类实例变量。