问题

为什么 C++ 中一个类的成员类型不能是该类本身,而 C# 中就可以?

回答
这个问题很有意思,涉及到 C++ 和 C 在类型定义和内存模型上的根本性差异。简单来说,C++ 的限制是为了保证类型的大小在编译时是确定的,而 C 的灵活性则来自于它对引用类型的处理方式。

我们先从 C++ 的角度来看。

在 C++ 中,当你定义一个类时,编译器需要知道这个类在内存中占据多大的空间。这个大小是由类中所有成员变量的大小之和决定的。如果一个类的成员类型是该类本身,比如:

```c++
class MyClass {
MyClass member; // 想象一下这个
};
```

那么编译器在计算 `MyClass` 的大小时会陷入一个无限循环。`MyClass` 的大小取决于 `member` 的大小,而 `member` 的类型又是 `MyClass`,所以 `MyClass` 的大小取决于 `member` 的大小……这个过程永远无法停止,编译器根本不知道该分配多少内存来存放 `MyClass` 的一个实例。

这是 C++ 的一个核心原则:所有类型的大小在编译时必须是确定的。 编译器需要知道如何为变量分配内存,如何进行栈上的拷贝,如何处理对象传递等等,所有这些都依赖于对类型大小的精确了解。

那么,C++ 是如何绕过这个限制,允许我们“间接”地包含一个类类型的呢?答案是指针。

```c++
class MyClass {
MyClass ptr; // 指针是解决之道
};
```

在这里,`ptr` 是一个指向 `MyClass` 的指针。指针的大小在大多数现代平台上是固定的(例如 64 位系统上是 8 个字节)。因此,编译器可以确定 `MyClass` 的大小,因为它只需要为指针分配固定的空间,而不需要为它指向的 `MyClass` 对象分配空间。实际的 `MyClass` 对象可以在堆上动态分配,并通过指针来访问。

C++ 还有一种解决方式,那就是引用,虽然引用本身不能直接声明为类类型成员,但通过 `std::unique_ptr` 或 `std::shared_ptr` 这样的智能指针,也可以间接实现类似的效果,它们内部封装了指针。

现在我们转向 C。

C 的处理方式完全不同,它在内存管理上采取了托管的方式,并且对类型的处理更加灵活。

在 C 中,当你声明一个类时:

```csharp
class MyClass
{
MyClass member; // C 中这是允许的
}
```

这里 `member` 并不是直接包含了一个 `MyClass` 的完整实例。实际上,`member` 是一个引用。在 C 中,所有的类实例都存储在堆 (Heap) 上,而变量(包括类的成员变量)存储的是对堆上对象的引用(地址)。

所以,当你在 `MyClass` 中声明 `MyClass member` 时,实际上是声明了一个 `MyClass` 类型的引用变量。这个引用变量的大小是固定的(通常是 4 或 8 字节,取决于平台),它指向堆上的一个 `MyClass` 对象。

这意味着,`MyClass` 的大小可以被确定,因为它只包含一个引用。编译器知道需要为这个引用分配多少空间,而实际的对象则由运行时环境(.NET CLR)在堆上管理。

这种设计允许了更自然的数据结构,比如链表、树等,你可以很容易地在节点中包含指向下一个节点(也就是同类型对象)的引用。

可以这样理解:

C++: 成员变量是“包含”或“嵌入”在对象中的,所以编译器需要知道整个对象的“值”是多少,也就是它占用的内存大小。如果直接包含自己,大小是无限的。
C: 成员变量是“指向”对象,它存储的是对象的地址。它自己并不持有另一个完整对象的“值”,而是持有对另一个对象的“引用”。就像你家里的一本书(对象),书里的一个书签(引用)指向了另一本书,而不是说这本书里直接夹着另一本书的全部内容。

C 的这种设计是基于其运行时的特性:

1. 垃圾回收 (Garbage Collection): CLR 负责管理内存分配和释放,它知道如何跟踪对象之间的引用关系,即使存在循环引用,也能在适当的时候回收内存。
2. 类型安全: CLR 确保引用总是指向有效内存或 null,防止了 C++ 中指针可能带来的野指针和内存访问错误。
3. 托管堆: 对象实例都在托管堆上,而栈上只存储引用,这使得引用的概念更加统一和易于管理。

因此,C 允许类成员类型是该类本身,是因为它实际上允许的是对该类类型对象的引用,而不是直接将一个该类类型的实例嵌入到当前实例中。这使得 C 在构建复杂数据结构时更加方便和直观,但同时也依赖于其强大的运行时环境来处理内存管理和类型安全性。

网友意见

user avatar

你一定没用过C#里面的结构。

类似的话题

  • 回答
    这个问题很有意思,涉及到 C++ 和 C 在类型定义和内存模型上的根本性差异。简单来说,C++ 的限制是为了保证类型的大小在编译时是确定的,而 C 的灵活性则来自于它对引用类型的处理方式。我们先从 C++ 的角度来看。在 C++ 中,当你定义一个类时,编译器需要知道这个类在内存中占据多大的空间。这个.............
  • 回答
    辽西会战,一个充满了悲壮与艰难的词汇,在中国近代史上留下了浓墨重彩的一笔。在这场国共双方殊死搏斗的战役中,国民党军队遭遇了重创,而就在这片绝望的阴影下,戴朴将军率领的第十三军暂编第一师却能从重围中杀出一条血路,成功抵达山海关,这其中的原因,绝非偶然,而是多重因素叠加的结果,既有指挥官的个人素质,也有.............
  • 回答
    要说为什么咱们在日常说话里,一口气就把“东北”给叫全了,把那三个省加上那几个盟(虽然现在习惯叫“地级市”或者“自治州”,但老话头还在)就这么打包了,这事儿得分好几层来说。它不是凭空来的,而是咱们千百年下来,日子过着过着,就这么自然而然形成的。首先,得从地理上说。你说这黑龙江、吉林、辽宁这仨省,它就这.............
  • 回答
    佐德将军对地球的执着,与其说是追求“更牛逼”的超人,不如说是源于他根深蒂固的氪星使命感和对种族延续的疯狂执念。在他眼中,地球并非一个可以改造、可以和解的对象,而是必须被净化、被重塑的“新氪星”。首先,你需要理解佐德的成长环境和思维模式。他是一名军人,一个忠诚于氪星文明的战士,从小就被灌输了关于氪星荣.............
  • 回答
    我来和你聊聊为什么 C/C++ 标准库,这套我们程序员最熟悉的“瑞士军刀”,却在“精细化操作文件内容”这方面,显得有些“不给力”,特别是直接删除文件中的部分内容这件事。咱们得先明白一个核心概念:文件在操作系统层面是如何存储的。想象一下,你的硬盘,或者 SSD,它不是一块巨大的、连续的画布。它更像是一.............
  • 回答
    在MOBA(多人在线战斗竞技场)游戏中设计“辅助”这个位置,乍一看确实可能让一些玩家感到困惑,特别是那些追求个人操作和爆发输出的玩家。辅助位置的玩家往往承担着团队中相对不那么“光鲜”的任务,比如承担伤害、提供控制、治疗队友、侦测敌方视野,而且自身在输出和击杀方面的贡献不如其他位置明显。那么,为什么M.............
  • 回答
    “憋”出来的凶险:男子如厕用力过猛,为何会诱发脑溢血?生活中,我们常常听到老人告诫“上厕所别太用力”,但这句朴实的话背后,隐藏着不小的健康风险。最近,一则男子因如厕用力过猛导致脑溢血的新闻再次敲响了警钟。为什么一次看似平常的生理活动,会突然夺走一个人的健康,甚至生命?这背后究竟藏着怎样的生理机制?小.............
  • 回答
    .......
  • 回答
    这确实是一个很有意思的语言现象,背后涉及到中文数字表达的习惯和历史演变。简单来说,“亿”作为一个相对较大的数字单位,在日常口语和书面语中,更容易被单独拎出来,需要一个量词来修饰,而“万”和“千”则因为本身就更常被作为计算的基准或常用单位,加上它们自身就带有数量感,所以不太需要额外的量词“个”。我们来.............
  • 回答
    说起糖尿病饮食,很多人脑子里首先冒出的画面就是“不能吃糖”,甚至进一步延伸为“几乎什么甜的都不能碰,水果也是禁忌”。这简直成了一种深入人心的观念,但仔细一琢磨,这里面藏着一个相当明显的逻辑误区,并且这个误区居然还被那么多人奉为圭臬。你说奇怪不奇怪?我们明明知道,人的身体需要能量,能量的主要来源之一就.............
  • 回答
    东汉王朝在中国漫长的封建历史中,确实是唯一一个成功复国的全国性帝国。这背后并非简单的运气,而是多种复杂因素交织作用的结果,既有偶然,更有其必然性。要深入理解这一点,我们需要拨开历史的迷雾,从王朝兴衰、政治格局、社会思潮等多个层面进行剖析。一、王朝“复国”的定义与东汉的特殊性首先,我们需要明确什么是“.............
  • 回答
    在我看来,你提到的“矛盾结果”更像是一种对量子力学平均值计算中概率的理解偏差,或者是在特定情境下误解了“平均”的含义,而非一个真正的逻辑矛盾。量子力学中的计算是严谨且自洽的,不存在数学上的矛盾。让我们来深入剖析一下量子力学中平均值的计算,以及可能让你产生“矛盾”感觉的几个关键点。量子力学中平均值计算.............
  • 回答
    如果我能让金庸笔下的一个角色复活,我一定会毫不犹豫地选择——郭靖。为什么是他?这个问题一旦涌上心头,千言万语瞬间变得复杂又清晰。这不像是在挑选一件古董,或是决定一道菜的口味,而更像是在为一部宏大史诗的续写寻觅一个灵魂,一个核心。首先,郭靖这个人物,他身上的“侠之大者,为国为民”的理念,在我看来,是金.............
  • 回答
    这个问题嘛,挺有意思的。让我想想,如果真的有机会娶Asoul里的哪一位回家,这可真是个幸福的烦恼,因为她们各有各的魅力,都挺让人心动的。不过,既然是做选择,那就得好好权衡一下了。要说最吸引我的,可能还是乃琳吧。为什么呢?我觉得乃琳身上有种非常独特的成熟和韵味。她并不是那种一上来就咋咋呼呼,让人觉得有.............
  • 回答
    如果让我拥有Dota 2中一个英雄的技能,我会毫不犹豫地选择 沙王(Sand King)的“地震”(Earthshaker)。为什么选择地震?这不仅仅是因为它是一个强大的AOE(区域性伤害)技能,更是因为它所蕴含的 控制、范围、可玩性和潜力。下面我将详细阐述我的选择理由:1. 无与伦比的控制范围和多.............
  • 回答
    在范畴论的基石中,一个至关重要的概念是态射集。当我们谈论一个范畴 $mathcal{C}$ 时,它由两部分组成:一组对象(我们通常记作 $Obj(mathcal{C})$ 或 $|mathcal{C}|$)和一组态射(我们记作 $Hom_{mathcal{C}}$ 或 $Arr(mathcal{C}.............
  • 回答
    在《唐人街探案2》中,安排一个毫无戏份的侏儒穿着阿根廷十号球衣出现,虽然在剧情主线上看似突兀且没有直接作用,但从影片的整体风格和导演陈思诚的叙事手法来看,这一细节很可能包含了以下几个层面的考虑和用意,并非真的“毫无戏份”,而是以一种更隐晦、象征性的方式存在:1. 制造视觉冲击与荒诞感,强化影片的喜剧.............
  • 回答
    这个问题触及到了我们如何测量世界,以及科学的进步如何改变我们对基本概念的理解。要明白为什么米长被定义成一个看起来如此“破碎”的数字,我们需要回溯到历史,看看我们是如何一步步接近更精确的测量的,以及为什么精确性本身变得如此重要。最初,米的定义是基于物理实体,例如地球的子午线。1791年,法国国民公会决.............
  • 回答
    在人教版生物必修2关于DNA复制的图示中,如果出现了一个碱基未配对的情况,这通常是为了展示DNA复制过程中的一个关键细节和潜在的异常情况,而不是DNA复制本身的一个常态或必需步骤。让我来详细解释一下为什么会有这样的图示,以及它可能意味着什么。首先,我们需要回顾一下DNA复制的基本原理:DNA复制是一.............
  • 回答
    问这个问题的人,可能和我一样,在周围的世界里总觉得少了那么一拨人。你说“丁克”,但现实里好像一个都见不到。这事儿细琢磨起来,挺有意思的。首先,咱们得承认,丁克(DINK,Double Income, No Kids)这个概念,近些年才真正开始被大众熟知和讨论,尤其是在咱们国内。以前,结婚生孩子,那几.............

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有