C#继承中的override(重写)与new(覆盖)用法
刚接触C#编程,我也是被override与new搞得晕头转向。于是花了点时间翻资料,看博客,终于算小有领悟,把学习笔记记录于此。
首先声明一个父类Animal类,与继承Animal的两个子类Dog类与Cat类。父类Animal中有一个Say方法,而子类Dog与Cat分别override(重写)与new(覆盖)了Say方法。
让我们通过实例来看一下这两者有什么相同与不同之处。
public class Animal
{
public virtual void Say()
{
Console.WriteLine("Hello,Animal");
}
}
public class Dog : Animal
{
public override void Say()
{
Console.WriteLine("Hello,Dog");
}
}
public class Cat : Animal
{
public new void Say()
{
Console.WriteLine("Hello,Cat");
}
}
首先说override与new的共同点:
- 都是子类在重新实现父类中签名相同的方法时使用。
- 当声明一个子类对象时,调用这个方法,调用的都是子类中实现的方法。
例如:
class Program
{
static void Main(string[] arge)
{
Dog d = new Dog();
Cat c = new Cat();
d.Say();//调用override的方法
c.Say();//调用new的方法
}
}
输出是:
Hello,Dog
Hello,Cat
此时调用的分别是Dog与Cat类中实现的Say方法。
3.都不会影响父类自身的方法。
如:
class Program
{
static void Main(string[] arge)
{
Animal a = new Animal();
a.Say();//调用父类方法。未受影响。
}
}
此时的输出是:
Hello,Animal
下面说两者的不同之处:
1.
(1)override:父类方法必须用virtual修饰,表示这个方法是虚方法,可以被重写。否则不能被重写。
(2)new : 父类方法不必使用virtual修饰。
2.
(1)override : 使用override时,父类中必须存在签名完全相同的virtual方法。否则编译不通过。
如果我在Dog类的Say增加一个string类型的形参,则编译器会提示:没有合适的方法可以重写。

(2)new : 使用new时,父类中最好存在签名相同的方法。如果没有,VS会有提示,但编译不会报错。此时,new关键字便没有了意义。
如果我在Cat类的Say增加一个string类型的形参,VS会提示:new关键字不是必须的。

3.当子类中存在与父类方法签名相同的方法,而没有被override或new修饰时,默认为new。
也就是说,override必须写,而new可以不写(不推荐)。
4.这是最重要的一点。以上三点都是使用方法的区别,而这一点是两者在实际使用时效果的区别。
(1)override :重写后,当子类对象转换为父类时,无法访问被重写的虚方法。也就是,被子类重写后,虚方法在子类对象中便失效了。
如:
class Program
{
static void Main(string[] arge)
{
Dog d = new Dog();
Animal a = d as Animal;//子类转换为父类。注意此时a与d指向同一对象,但d是作为Dog类访问,而a是作为Animal类访问
d.Say();//此时调用的是override的方法
a.Say();//此时调用的也是override的方法
}
}
输出为:
Hello,Dog
Hello,Dog
两次调用的都是Dog中重写的Say方法
(2)new : 覆盖后,当子类对象转换为父类,可以访问被覆盖的父类方法。也就是,转换为父类后,子类new的方法便失效了,此时调用的是父类方法。
当其再转换为子类时,调用的又变为子类方法。
如:
class Program
{
static void Main(string[] arge)
{
Cat c = new Cat();
Animal a = c as Animal;//子类转换为父类。注意此时a与c指向同一对象,但c是作为Cat类访问,而a是作为Animal类访问
c.Say();//此时调用的是new的方法
a.Say();//此时调用的是父类中的方法
}
}
此时的输出为:
Hello,Cat
Hello,Animal
内存原理:
我们都知道,调用对象的方法,实际上是访问对象方法在内存中的地址。那么既然可以通过c.Say()访问到父类的方法,说明在对象c中,也有Animal类的Say方法。
事实上,当子类继承父类的时候,父类中所有方法、字段(包括私有的)都会复制一份放在子类中。而我们所谓的重写和覆盖,重写、覆盖的是存放在子类中的,复制出来的方法,而不是父类中的方法,所以当然不会对父类产生任何影响。而不能调用私有的、或者被重写的方法或字段,是由于无权访问,而不是内存中不存在。
C#继承中的override(重写)与new(覆盖)用法的更多相关文章
- java学习笔记-继承中super关键字
背景: 在java继承的概念中我们得知,被声明为私有的类成员对所属的类来说仍然是私有的.类之外的任何代码都不能访问,包括子类. super关键字的两种用法: 1.用于调用超类的构造函数: 2.用于访问 ...
- 继承中的隐藏(hide)重写(Override)和多态(Polymorphism)
继承中的隐藏:(不要使用隐藏,语法没有错误但是开发项目时会被视为错误) 在继承类中完全保留基类中的函数名 //基类,交通工具 class Vehicle { public void Run() { C ...
- Java:面向对象(继承,方法的重写(overide),super,object类及object类中方法的重写,父子类代码块执行顺序)
继承: 1.继承是对某一匹类的抽象,从而实现对现实世界更好的建模. 2.提高代码的复用性. 3.extends(扩展),子类是父类的扩展. 4.子类继承父类可以得到父类的全部属性和方法.(除了父类的构 ...
- 【转载】 C++多继承中重写不同基类中相同原型的虚函数
本篇随笔为转载,原文地址:C++多继承中重写不同基类中相同原型的虚函数. 在C++多继承体系当中,在派生类中可以重写不同基类中的虚函数.下面就是一个例子: class CBaseA { public: ...
- c#中override重写和new隐藏
最近学习c#,昨晚看书看到多态.由于个人本身是从事java开发,于是拿来做对比便是自然的. 进入主题吧. c#中,子类要重写基类的方法,必须要基类声明中带有virtual关键字方法或者带有abstra ...
- Java多态机制和继承中重写重载
关于Java中多态机制 http://www.cnblogs.com/chenssy/p/3372798.html 这篇博文讲的很透彻 大体意思是 多态定义: 多态就是指程序中定义的引用变量所指向的具 ...
- 转载MSDN 在ASP.NET 中执行 URL 重写
转载文章原网址 http://msdn.microsoft.com/zh-cn/library/ms972974.aspx 摘要:介绍如何使用 Microsoft ASP.NET 执行动态 URL 重 ...
- Scala中的override
Scala中的override override是覆盖的意思,在很多语言中都有,在scala中,override是非常常见的,在类继承方面,它和java不一样,不是可写可不写的了,而是必须写的.如果不 ...
- Android继承BaseAdapter时要重写的函数的说明
原文来自:http://www.2cto.com/kf/201405/299601.html,我自己做了一些修改 Android中继承BaseAdapter后需要重写四个函数,但一般还要写一个构造函数 ...
随机推荐
- VC维含义的个人理解
有关于VC维可以在很多机器学习的理论中见到,它是一个重要的概念.在读<神经网络原理>的时候对一个实例不是很明白,通过这段时间观看斯坦福的机器学习公开课及相关补充材料,又参考了一些网络上的资 ...
- windows 2008 R2 断电重启进入修复模式
windows 2008 R2 意外断电重启进入修复模式 现在出现一个问题,就是当机房停电的时候,计算机自动进入到修复模式,当人不在机房的时候,容易造成服务器无法访问,我相信正常启动应该没什么问题吧, ...
- 教你ASP.NET中如何防止注入攻击
你应该在程序中验证所有的不信任输入.你应该假定所有的用户输入都是非法的.用户可以在应用程序中提供表单字段,查询字串,客户端cookies和浏览器环境值比如用户代理字串和IP地址等. 弱输入校验通常为注 ...
- gitlab与jenkins的自动化部署(通过webhook与ansilble)
gitlab与jenkins的自动化部署(通过webhook与ansilble) 1.部署介绍 gitlab服务器:192.168.1.49:80jenkins服务器:192.168.1.49:818 ...
- 【学习】js学习笔记:内置顶层函数eval()的兼容用法
今天学了一个内置顶层函数,eval();其作用是将字符串转换成javascript命令执行,但必须符合语法,否则会报错. 如果写成window.eval(),则其定义的变量会在全局生效. 但是,在IE ...
- Object类—复写equals方法,hashCode方法,toString方法
Object:所有类的根类. Object是不断抽取而来,具备着所有对象都具备的共性内容. class Person extends Object { private int age; Person( ...
- canvas图表详解系列(3):动态饼状图(原生Js仿echarts饼状图)
本章建议学习时间4小时 学习方式:详细阅读,并手动实现相关代码(如果没有canvas基础,需要先学习前面的canvas基础笔记) 学习目标:此教程将教会大家如何使用canvas绘制各种图表,详细分解步 ...
- PowerApps 经验总结
Label的padding不要设置成0,因为有些字体会超出当前的框架,造成Clip效果 Label的AutoHeight并不会将原来自带的Height删除,所以有的时候空间更新属性出现问题,就会造成显 ...
- VisualStudio 扩展开发
本文主要:如何开发一个 visual Studio 扩展,其实扩展也叫插件. 那么就是如何开发一个 vs插件. 我写这博客时候,是我在开发一个插件:编码规范工具.记录的是我从不知道到发布插件,如果遇到 ...
- 从零开始教你封装自己的vue组件
组件(component)是vue.js最强大的功能之一,它可以实现功能的复用,以及对其他逻辑的解耦.但经过一段时间的使用,我发现自己并没有在业务中发挥出组件的最大价值.相信很多刚开始使用vue的朋友 ...