C# 结构体(struct)和类(class)有以下区别

1. 数据存储方式

    • 是引用类型。当创建一个类的对象并将其赋值给另一个变量时,实际上是复制了对象的引用。这意味着多个变量可以引用同一个对象。如果通过一个变量修改了对象的内容,那么通过其他引用该对象的变量也会看到这个修改。
    • 例如,假设有一个Player类,代表游戏中的玩家角色。
class Player
{
    public int health;
    public string name;
}
Player player1 = new Player();
player1.health = 100;
player1.name = "John";
Player player2 = player1;
player2.health = 50;
// 此时player1.health也会变为50,因为player1和player2引用的是同一个对象
  • 结构体
    • 是值类型。当把一个结构体变量赋值给另一个变量时,会复制结构体的所有成员的值。对其中一个结构体变量的修改不会影响另一个结构体变量。
    • 例如,定义一个表示游戏中二维坐标的结构体。  
struct Coordinate
{
    public int x;
    public int y;
}
Coordinate point1 = new Coordinate();
point1.x = 10;
point1.y = 20;
Coordinate point2 = point1;
point2.x = 30;
// 此时point1.x仍然是10,因为point2是point1的副本,它们是相互独立的值类型变量

2. 内存分配

    • 对象存储在堆(Heap)内存中。堆是一个用于动态分配内存的区域,当创建一个类的新对象时,系统会在堆中分配足够的空间来存储对象的成员变量以及一些额外的信息(如对象的类型信息等)。这使得类对象的生命周期可以比较灵活,只要有引用指向它,对象就会一直存在于内存中。
    • 不过,这也意味着需要对内存进行管理,在不需要对象时要确保及时释放内存,以避免内存泄漏。在 Unity 中,虽然有自动的垃圾回收机制(Garbage Collection,GC)来回收不再使用的对象内存,但频繁的创建和销毁大型类对象可能会导致性能问题,因为 GC 需要花费时间来清理内存。
  • 结构体
    • 结构体变量通常存储在栈(Stack)内存中。栈是一种先进后出的数据结构,用于存储局部变量等。栈内存的分配和释放是自动的,当一个结构体变量超出其作用域(如函数结束)时,它所占用的栈内存会自动被回收。由于结构体的大小在编译时就已经确定,所以栈内存的管理相对简单高效。
    • 不过,如果结构体非常大(例如包含大量成员或者嵌套了其他大型结构体),频繁地复制结构体变量可能会导致性能开销,因为每次赋值都要复制所有成员的值。

3. 继承特性

    • 支持继承。一个类可以继承自另一个类,从而继承父类的成员(字段、方法、属性等)。这使得代码可以实现多态性,即通过基类的引用可以调用派生类的重写方法,这是面向对象编程中的一个重要特性。
    • 例如,有一个Enemy基类,它有一个Attack方法,然后有不同类型的敌人(如MeleeEnemyRangedEnemy)继承自Enemy类并可以重写Attack方法
class Enemy
{
    public virtual void Attack()
    {
        // 基础攻击逻辑
    }
}
class MeleeEnemy : Enemy
{
    public override void Attack()
    {
        // 近战攻击逻辑
    }
}
class RangedEnemy : Enemy
{
    public override void Attack()
    {
        // 远程攻击逻辑
    }
}
  • 结构体
    • 不支持继承。结构体不能从其他结构体或类继承,也不能作为其他结构体或类的基类。不过,结构体可以实现接口,通过接口来定义一组行为规范,从而在一定程度上实现类似于多态的效果。
    • 例如,定义一个IDamageable接口,结构体可以实现这个接口来表示它可以受到伤害。
interface IDamageable
{
    void TakeDamage(int damage);
}
struct Building : IDamageable
{
    public int health;
    public void TakeDamage(int damage)
    {
        health -= damage;
    }
}

4. 默认构造函数

    • 如果没有定义任何构造函数,编译器会自动提供一个默认的无参数构造函数。这个默认构造函数会初始化对象的成员变量为它们的默认值(例如,引用类型为null,数值类型为 0 等)。当然,也可以自己定义有参数或无参数的构造函数来初始化对象。
    • 例如,对于之前的Player类,即使没有定义构造函数,也可以这样创建对象:
Player player = new Player();
  • 结构体
    • 编译器会自动提供一个默认的无参数构造函数,这个构造函数会将结构体的所有成员初始化为它们的默认值。但是,如果定义了自己的构造函数,编译器就不会再提供默认的无参数构造函数了。
    • 例如,对于Coordinate结构体,如果定义了一个有参数的构造函数:
struct Coordinate
{
    public int x;
    public int y;
    public Coordinate(int initialX, int initialY)
    {
        x = initialX;
        y = initialY;
    }
}

5. 用途场景

    • 适用于表示复杂的、具有行为和状态的对象,尤其是当对象需要继承和多态性来实现灵活的设计时。在 Unity 游戏开发中,游戏中的角色、场景中的复杂物体、各种管理器(如资源管理器、场景管理器等)通常都用类来实现。
    • 例如,游戏中的角色类可能包含移动、攻击、动画播放等多种行为,并且角色之间可能存在继承关系,如玩家角色和敌人角色都继承自一个通用的角色基类。
  • 结构体
    • 更适合表示简单的数据集合,这些数据通常是相互关联的,并且不需要继承和复杂的行为。在 Unity 中,常用于表示简单的几何数据(如点、向量等)、配置数据或者临时的数据存储结构。
    • 例如,在一个射击游戏中,子弹的位置和方向可以用结构体来表示,因为它主要是作为一个简单的数据容器,方便在不同的函数之间传递和处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cxy15978

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值