基类的实例如何保存派生类的实例?

发布于 2024-12-14 19:26:31 字数 648 浏览 5 评论 0原文

我担任 .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 的所有空间,甚至更多。但事实并非如此,为什么呢?

我知道我问了一个非常愚蠢的问题,但是有人能给我更详细的答案吗?从内存或编译器的角度来看会更好。

I have been a .Net coder (can not say I am a programmer) for 2 years. There is one question that I can not understand for years, that is how could an instance of the base class hold an instance of the derived class?

Suppose we have two classes:

class BaseClass
{
    public A propertyA;
    public B propertyB;
}

class DerivedClass :BaseClass
{
    public C propertyC;

}

How could this happen:

BaseClass obj = new DerivedClass ()

I mean, the memory model of BaseClass, has no space for the newly added propertyC, so how could it still hold the value of propertyC?

On the other side, how could this can not happen:

DerivedClass  obj = new BaseClass()

I thought this is the correct way since the memory model of DerivedClass has all the spaces for the BaseClass and even more. But this is not true, why?

I know I am asking a really stupid question, but could someone give me a more detail answer of this? It would be better from the perspective of the memory or compiler.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

爱,才寂寞 2024-12-21 19:26:31

因为(这个概念经常被误解)保存指针的变量的类型独立于它所指向的对象的实际具体类型。

因此,当您编写

BaseClass obj = new DerivedClass () 

BaseClass obj 的部分时,会在堆栈上创建一个新的引用变量,编译器会理解该引用以保存对来自 < 或派生自 < 的内容的引用。代码>基类。

读取 = new DerivedClass () 的部分实际上创建了一个 DerivedClass 类型的新对象,将其存储在堆上,并存储了一个 指向 obj 指向的内存位置中的该对象的指针。堆上的实际对象 DerivedClass;这被称为对象的具体类型

变量 obj 被声明为 BaseClass 类型。这不是一个具体类型,它只是一个变量类型,它仅限制编译器将地址存储到指向的变量中不是 BaseClass 或不是从 BaseClass 类型派生的对象。

这样做是为了保证无论您放入 obj 变量中的是什么,无论它是 BaseClass 还是 DerivedClass 的具体类型,它都将具有所有方法、属性和BaseClass 类型的其他成员。它告诉编译器,obj 变量的所有使用都应限制为仅使用 BaseClass 类的成员。

Because (and this concept is often misunderstood) the variable that holds the pointer is typed independantly from the actual concrete type of the object it points to.

So when you write

BaseClass obj = new DerivedClass () 

the part that says BaseClass obj creates a new reference variable on the Stack that the compiler understands to hold a reference to something that is, or derives, from BaseClass.

The part that reads = new DerivedClass () actually creates a new object of type DerivedClass, stores it on the Heap, and stores a pointer to that object in the memory location that obj points to. The actual object on the Heap is a DerivedClass; this is referred to as the concrete type of the object.

The variable obj is declared to be of type BaseClass. This is not a concrete type, it is just a variable type, which only restricts the compiler from storing an address into the variable that points to an object which is not a BaseClass or which does not derive from the type BaseClass.

This is done to guarantee that whatever you put into the obj variable, no matter whether it is a concrete type of BaseClass or DerivedClass, it will have all the methods, properties and other members of the type BaseClass. It tells the compiler that all uses of the obj variable should be restricted to uses of only those members of the class BaseClass.

冰雪梦之恋 2024-12-21 19:26:31

由于 BaseClass 是引用类型,因此 obj 不是 BaseClass 对象。它是对 BaseClass 对象的引用。具体来说,它是对 DerivedClassBaseClass 部分的引用。

Since BaseClass is a reference type, obj is not a BaseClass object. It is a reference to a BaseClass object. Specifically, it is a reference to the BaseClass part of the DerivedClass.

゛清羽墨安 2024-12-21 19:26:31

当您这样说时:

BaseClass obj = new DerivedClass ()

您并不是在说“创建一个容器来包含此 BaseClass 对象,然后将这个更大的 DerivedClass 对象塞入其中”。

实际上,您正在创建一个 DerivedClass 对象,并且它是在足以容纳 DerivedClass 对象的内存空间中创建的。 .NET 框架永远不会忘记这个东西是一个 DerivedClass 的事实,也永远不会停止这样对待它。

但是,当您说选择使用 BaseClass 对象变量时,您只是创建一个指向已创建、分配和定义的对象的引用/指针,并且您的指针有点模糊。

就好像房间另一边的那个人是一个红头发的爱尔兰人,体重稍超重,牙齿不好,性格迷人,名叫吉米,但你只是把他称为“那边的那个家伙”。尽管您模糊的描述完全准确,但您对他的描述含糊不清这一事实并不会改变他的身份或他的任何细节。

When you say this:

BaseClass obj = new DerivedClass ()

You are NOT saying "Create a container to contain this BaseClass object, and then cram this bigger DerivedClass object into it".

You are in fact creating a DerivedClass object, and it is being created in a memory space sufficient for a DerivedClass object. Never does the .NET framework lose track of the fact this this thing is specifically a DerivedClass, nor does it ever stop treating it as such.

However, when you say choose to use a BaseClass object variable, you are just creating a reference/pointer to that object that has already been created and allocated and defined and all that, and your pointer is just a little bit more vague.

It's like that guy over there on the other side of the room is a red-headed Irish slightly-overweight chicken-farmer with bad teeth and charming personality named Jimmy, but you are just referring to him as "that dude over there". The fact that you are being vague in describing him does not change what he is or any of his details, even though your vague description is entirely accurate.

岁月蹉跎了容颜 2024-12-21 19:26:31

答案逐字复制了另一位用户 jk 在 Stackoverflow 上针对完全相同的问题所写的内容。

如果我告诉你我有一只狗,你就可以放心地假设我有一只狗。

如果我告诉你我有一只宠物,你不知道那个动物是不是狗,它
可能是一只猫,甚至可能是一只长颈鹿。在不知道一些额外的情况下
您不能放心地假设我有一只狗的信息。

类似地,派生对象是基类对象(因为它的子对象
class),因此可以由基类指针指向。然而一个基地
类对象不是派生类对象,因此不能分配给
派生类指针。

(您现在听到的吱吱声是类比拉伸)

假设您现在想给我的宠物买一件礼物。

在第一个场景中,你知道它是一只狗,你可以给我买一条皮带,
大家都很高兴。

在第二个场景中,我还没有告诉你我的宠物是什么,所以如果你是
无论如何你都要给我买件礼物你需要知道我不知道的信息
告诉过你(或者只是猜测),你给我买一条皮带,如果事实证明我真的
养了一只狗,大家都很高兴。

但是,如果我真的养了一只猫,那么我们现在就知道你做了坏事
假设(演员)并有一只不快乐的猫拴在皮带上(运行时错误)

Answer copied verbatim from what another user, jk, wrote on a exactly same question here on Stackoverflow.

If I tell you I have a dog, you can safely assume that I have a dog.

If I tell you I have a pet, you don't know if that animal is a dog, it
could be a cat or maybe even a giraffe. Without knowing some extra
information you can't safely assume I have a dog.

similarly a derived object is a base class object (as its a sub
class), so can be pointed to by a base class pointer. however a base
class object is not a derived class object so can't be assigned to a
derived class pointer.

(The creaking you will now hear is the analogy stretching)

Suppose you now want to buy me a gift for my pet.

In the first scenario you know it is a dog, you can buy me a leash,
everyone is happy.

In the second scenario I haven't told you what my pet is so if you are
going to buy me a gift anyway you need to know information I havent
told you (or just guess), you buy me a leash, if it turns out I really
did have a dog everyone is happy.

However if I actually had a cat then we now know you made a bad
assumption (cast) and have an unhappy cat on a leash (runtime error)

蛮可爱 2024-12-21 19:26:31

这是可能的,因为内存为基类和派生类分配的方式。在派生类中,首先分配基类的实例变量,然后分配派生类的实例变量。当将基类引用变量分配给派生类对象时,它会看到它期望的基类实例变量以及“额外”的派生类实例变量。

This is possible because of the way memory is allocated for base and derived classes. In a derived class, the instance variables of the base class are allocated first, followed by the instance variables of the derived class. When a base class reference variable is assigned to a derived class object, it sees the base class instance variables that it expects plus the "extra" derived class instance variables.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文