继承与重写:new与override的内存解析

需积分: 10 5 下载量 97 浏览量 更新于2025-01-01 收藏 39KB DOC 举报
本文将深入探讨C#编程语言中两种重写方法——`override`和`new`的关键概念以及它们在内存机制上的体现。通过分析一个简单的继承实例,我们将揭示实例化过程中父类与子类成员如何分配内存,以及这两种重写关键字如何影响方法的调用。 在C#中,`override`和`virtual`关键字用于实现多态性,允许子类重写父类的虚拟方法。而`new`关键字则用于隐藏父类的同名成员。在内存机制上,`override`和`new`有着明显的区别。 首先,我们来看一下继承实例化的机制。当创建一个子类对象时,会经历以下步骤: 1. **实例化父类成员**:子类实例首先为父类的公有成员分配内存,并初始化这些成员的值。在给出的例子中,父类`Person`有`name`变量和`age`变量(初始值为10),以及一个`public virtual void printA()`虚方法和两个非虚方法`printC()`和`printD()`。 2. **实例化子类成员**:接着,子类`Student`的独有成员被实例化,这包括`num`变量以及`override`重写`printA()`和`new`重写`printD()`的方法。 3. **基类引用**:子类对象中包含一个基类引用,通常在C#中称为`base`,在Java中为`super`。这个引用指向父类部分的内存地址,使得可以通过子类对象访问父类的成员。 当我们创建一个`Student`对象`stu`并将其强制转换为`Person`类型,即`person pe = (person)stu`,`pe`实际上是指向`stu`内的父类部分的引用。这意味着,通过`pe`调用的方法将基于父类的行为,除非这些方法在子类中被重写。 对于`override`关键字,它指示子类方法重写了父类的虚方法。在`Student`类中,`printA()`被`override`重写,因此无论通过`stu`还是`pe`调用`printA()`,都会执行子类的版本,输出"BBBBBBBB"。这是因为虚方法的调用是动态绑定的,它会在运行时根据实际对象的类型决定调用哪个方法。 然而,对于`new`关键字,它不是重写,而是隐藏。在`Student`类中,`printD()`被`new`关键字修饰,这意味着它隐藏了父类的`printD()`方法。如果通过`stu`调用`printD()`,会执行子类的新版本,输出"EEEEEEE"。但当通过`pe`调用`printD()`时,由于`pe`只看到父类的成员,因此会调用父类的`printD()`方法,输出"DDDDDDDD"。这是静态绑定的结果,方法的调用基于变量的声明类型,而非实际对象的类型。 总结来说,`override`和`new`在内存机制上的差异主要体现在方法调用的行为上。`override`实现的是多态,允许子类改变父类虚方法的行为,而`new`则是子类隐藏父类成员的一种方式,提供了另一种方法实现。在实际编程中,选择使用哪种关键字应根据设计需求和预期的行为来决定。