C# new和override的区别和用途

2023-05-16

override
1. override是派生类用来重写基类中方法的;

2. override不能重写非虚方法和静态方法;

3. override只能重写用virtual、abstract、override修饰的方法;

4. 不能使用修饰符 new、static、virtual 或 abstract 来修改 override 方法。

new
1. new是派生类用来隐藏基类中的方法的;也就是说在派生类中“看不到”基类中的方法,说白了,其实就是基类和派生类的这2个函数,虽然名字相同,但可以看成是名字不一样的2个函数,没啥联系,基类和派生类的函数是共存的。

2. 如果要在派生类中隐藏(不是重写)基类中的方法,而没有使用new关键字,编译时会出现一个警告,提示如果是要隐藏基类中的方法,请使用new关键字;

3. 派生类可以隐藏基类中的虚方法,也可以隐藏基类中的普通方法。

4. 如果在派生类中用private来修饰new 方法,那么只在该派生类中隐藏了基类中的方法,在该派生类之外,相当于没有隐藏基类中的方法;

5. 如果在派生类中隐藏了基类中的方法,在该派生类的派生类中,将延续对该派生类对基类方法的隐藏。

现在不在状态或者比较晕的童鞋,不用担心,下面我用简单的例子来讲解一下,便于理解。

override的例子
public class A
{
    public A()
    {
        Console.WriteLine('A');
    }
    public virtual void Fun()
    {
        Console.WriteLine("A.Fun()");
    }
}
 
public class B : A
{
    public B()
    {
        Console.WriteLine('B');
    }
 
    public override void Fun()
    {
        Console.WriteLine("B.Fun()");
    }
}
声明B类型的对象:

B test = new B();
test.Fun();

输出结果是:

A
B
B.Fun()

该结果中,先输出A,在输出B,说明初始化的时候,先执行基类,再执行化子类的构造函数

声明A类型的对象:

A test = new B();
test.Fun();

运行结果:

A
B
B.Fun()

说明无论是父类型还是子类型的对象 ,当使用override时,父类的虚函数完全被子类的函数给“覆盖”了。这个例子相信是No Problem的。

new的例子
public class A
{
    public A()
    {
        Console.WriteLine('A');
    }
    public virtual void Fun()
    {
        Console.WriteLine("A.Fun()");
    }
}
 
public class B : A
{
    public B()
    {
        Console.WriteLine('B');
    }
 
    public new void Fun()
    {
        Console.WriteLine("B.Fun()");
    }
}
声明B类型的对象:

B test = new B();
test.Fun();

输出结果是:

A
B
B.Fun() ----此时与override的效果相同

声明A类型的对象:

A test = new B();
test.Fun();

运行结果:

A
B
A.Fun() ----此时,与override的情况不一样了。。。

简单的结论:

1.new声明的方法,当使用子类的类型来调用的时候,它会运行子类中的函数,当类型是基类的话 ,则使用基类的函数来执行,可以简单的记忆:

override--覆盖(父类的没了,始终是儿子),new--新的(父子共存)

PS:只有使用virtual定义基类中的函数,并使用override标记子类的函数,才可以达到多态类----始终调用子类的方法

2.子类中override父类的方法,父类的方法一定要是virtual,而在子类中new父类的方法,父类的方法不一定要是virtual

3.抽象类中的抽象方法,必须要被子类override,不能new

4.override可以与sealed关键词连用: sealed override void F(),而new不行。被sealed修饰过的方法,不能再被子类重写

/*********************************2********************************

override

1. override是派生类用来重写基类中方法的;

2. override不能重写非虚方法和静态方法;

3. override只能重写用virtual、abstract、override修饰的方法;

4. 不能使用修饰符 new、static、virtual 或 abstract 来修改 override 方法。

new

1. new是派生类用来隐藏基类中的方法的;也就是说在派生类中“看不到”基类中的方法;

2. 如果要在派生类中隐藏(不是重写)基类中的方法,而没有使用new关键字,编译时会出现一个警告,提示如果是要隐藏基类中的方法,请使用new关键字;

3. 派生类可以隐藏基类中的虚方法,也可以隐藏基类中的普通方法。

4. 如果在派生类中用private来修饰new 方法,那么只在该派生类中隐藏了基类中的方法,在该派生类之外,相当于没有隐藏基类中的方法;

5. 如果在派生类中隐藏了基类中的方法,在该派生类的派生类中,将延续对该派生类对基类方法的隐藏。

代码:

复制代码

复制代码


 class A
    {
        public virtual void Func() // 注意virtual,表明这是一个虚拟函数 
        {
            Console.WriteLine("Func In A");
        }
    }
    class B : A // 注意B是从A类继承,所以A是父类,B是子类 
    {
        public override void Func() // 注意override ,表明重新实现了虚函数 
        {
            Console.WriteLine("Func In B");
        }
    }
    class C : B // 注意C是从B类继承,所以B是父类,C是子类 
    {
    }
    class D : A // 注意D是从A类继承,所以A是父类,D是子类 
    {
        public new void Func() // 注意new,表明覆盖父类里的同名类,而不是重新实现 
        {
            Console.WriteLine("Func In D");
        }
    }
    class E : D // 注意E是从D类继承,所以D是父类,E是子类 
    {
      
    }
    class F : A
    {
        private new void Func() //注意new关键字前有private修饰符,故该隐藏只在F类内有效
        {
            Console.WriteLine("Func In F");
        }

        public void Func2() 
        {
            Func(); //在F类内隐藏了基类的Func方法,故此处调用的private new void Func()
        }
    }


 static void Main(string[] args)
        {
            A a; // 定义一个a这个A类的对象.这个A就是a的申明类 
            A b; // 定义一个b这个A类的对象.这个A就是b的申明类 
            A c; // 定义一个c这个A类的对象.这个A就是c的申明类 
            A d; // 定义一个d这个A类的对象.这个A就是d的申明类 
            A e; // 定义一个e这个A类的对象.这个A就是e的申明类 
            A f; // 定义一个f这个A类的对象.这个A就是f的申明类 
            a = new A(); // 实例化a对象,A是a的实例类 
            b = new B(); // 实例化b对象,B是b的实例类 
            c = new C(); // 实例化c对象,C是c的实例类 
            d = new D(); // 实例化d对象,D是d的实例类 
            e = new E(); // 实例化e对象,E是e的实例类
            f = new F(); // 实例化f对象,F是f的实例类
            Console.WriteLine("a.Func();");
            a.Func(); // 执行a.Func:1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类A,就为本身 4.执行实例类A中的方法 5.输出结果 Func In A 
            Console.WriteLine("b.Func();");
            b.Func(); // 执行b.Func:1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类B,有重载的 4.执行实例类B中的方法 5.输出结果 Func In B 
            Console.WriteLine("c.Func();");
            c.Func(); // 执行c.Func:1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类C,无重载的 4.转去检查类C的父类B,有重载的 5.执行父类B中的Func方法 5.输出结果 Func In B 
            Console.WriteLine("d.Func();");
            d.Func(); // 执行d.Func:1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类D,无重载的(这个地方要注意了,虽然D里有实现Func(),但没有使用override关键字,所以不会被认为是重载) 4.转去检查类D的父类A,就为本身 5.执行父类A中的Func方法 5.输出结果 Func In A 
            Console.WriteLine("e.Func();");
            e.Func(); // 执行e.Func:E继承D,E.Func没有重写父类中的方法,相当于执行父类D中的Func方法,输出结果 Func In A 
            Console.WriteLine("f.Func();");
            f.Func(); // 执行f.Func:F类中虽然隐藏了基类中的Func方法,但是有private修饰符,该隐藏只在F类范围内有效。执行f.Func相当于执行其基类中的Func方法,输出结果 Func In A 
            
            D d1 = new D();
            Console.WriteLine("d1.Func();");
            d1.Func(); // 执行D类里的Func(),输出结果 Func In D 

            E e1 = new E();
            Console.WriteLine("e1.Func();");
            e1.Func(); // 执行E类里的Func(),输出结果 Func In D

            F f1 = new F();
            Console.WriteLine("f1.Func();");
            f1.Func(); // 执行F类里的Func(),输出结果 Func In A
            Console.WriteLine("f1.Func2();");
            f1.Func2(); // 执行F类里的Func2(),输出结果 Func In F
           
            Console.ReadLine();
        }  

花时间研究了一下overide和new的区别,但是产生了一个疑问:什么时候需要隐藏方法呢?

默认情况下,C# 方法不是虚方法 -- 如果将一种方法声明为虚方法,则继承该方法的任何类都可以实现其自己的版本。若要使方法成为虚方法,必须在基类的方法声明中使用 virtual 修饰符。然后,派生类可以使用 override 关键字重写基虚方法,或使用 new 关键字隐藏基类中的虚方法。如果 override 关键字和 new 关键字均未指定,编译器将发出警告,并且派生类中的方法将隐藏基类中的方法。有关更多信息,请参见编译器警告 CS0108。

为了在实践中演示上述情况,我们暂时假定公司 A 创建了一个名为 GraphicsClass 的类,您的程序使用该类。GraphicsClass 类似如下:

C#


class GraphicsClass
{
    public virtual void DrawLine() { }
    public virtual void DrawPoint() { }
}

  

您的公司使用此类,并且您在添加新方法时将其用来派生自己的类:

C#


class YourDerivedGraphicsClass : GraphicsClass
{
    public void DrawRectangle() { }
}

  

您在应用程序的使用过程中没有遇到任何问题,直到公司 A 发布了 GraphicsClass 的新版本,该新版本类似如下:

C#


class GraphicsClass
{
    public virtual void DrawLine() { }
    public virtual void DrawPoint() { }
    public virtual void DrawRectangle() { }
}

  

现在,GraphicsClass 的新版本中包含了一个称为 DrawRectangle 的方法。最初,一切正常。新版本仍与旧版本二进制兼容 -- 即使在计算机系统中安装新类,部署的所有软件仍将继续工作。在您的派生类中,对方法 DrawRectangle 的任何现有调用将继续引用您的版本。

但是,一旦使用 GraphicsClass 的新版本重新编译应用程序,您将收到来自编译器的警告。有关更多信息,请参见编译器警告 CS0108。

此警告提示您需要考虑您的 DrawRectangle 方法在应用程序中的工作方式。

如果想用您的方法重写新的基类方法,请使用 override 关键字,如下所示:

C#


class YourDerivedGraphicsClass : GraphicsClass
{
    public override void DrawRectangle() { }
}

  

override 关键字可确保派生自 YourDerivedGraphicsClass 的任何对象都将使用 DrawRectangle 的派生类版本。派生自 YourDerivedGraphicsClass的对象仍可以使用 base 关键字访问 DrawRectangle 的基类版本,如下所示:

C#


base.DrawRectangle();

  

如果不想用您的方法重写新的基类方法,则应注意下面的事项。为避免在两种方法之间引起混淆,可以重命名您的方法。重命名方法可能很耗时且容易出错,而且在某些情况下并不实用。但是,如果您的项目相对较小,则可以使用 Visual Studio 的重构选项来重命名方法。有关更多信息,请参见重构类和类型。

或者,也可以通过在派生类定义中使用关键字 new 来防止出现该警告,如下所示:

C#


class YourDerivedGraphicsClass : GraphicsClass
{
    public new void DrawRectangle() { }
}

  

使用 new 关键字告诉编译器您的定义将隐藏基类中包含的定义。这是默认行为。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# new和override的区别和用途 的相关文章

  • Window捕获消息机制-C#

    C 捕获鼠标消息 在C 中怎样禁用鼠标按键 xff0c 我们可以通过ImessageFilter接口下的PreFilterMessage方法 Application类的AddMessageFilter方法 xff0c RemoveMessa
  • MFC中动态创建控件及添加消息响应的方法实例

    动态控件是指在需要时由Create 创建的控件 xff0c 这与预先在对话框中放置的控件是不同的 一 创建动态控件 xff1a 为了对照 xff0c 我们先来看一下静态控件的创建 放置静态控件时必须先建立一个容器 xff0c 一般是对话框
  • Windows消息ID号查看

    WM NULL 61 0000 WM CREATE 61 0001 应用程序创建一个窗口 WM DESTROY 61 0002 一个窗口被销毁 WM MOVE 61 0003 移动一个窗口 WM SIZE 61 0005 改变一个窗口的大小
  • MFC和c#中模拟对另一进程的窗口按钮点击

    1 在自动化测试中经常要模拟窗口按钮的点击 参考文章 xff1a http blog csdn net blackboyofsnp article details 3372719 有时我们需要这么做 手动模拟按钮按下的事件 让程序做出与按钮
  • C#中进程间通信方式汇总

    一 进程间通讯的方式 进程间通讯的方式有很多 xff0c 常用的有共享内存 xff08 内存映射文件 共享内存DLL 剪切板等 xff09 命名管道和匿名管道 发送消息等几种方法来直接完成 xff0c 另外还可以通过socket口 配置文件
  • ubuntu shared folder to windows

    一 安装smb 执行命令行 xff1a sudo apt get install samba sudo apt get install smbfs 二 添加准备共享的文件夹 有如下三种配置共享文件夹的方法 xff0c 任选一种方法即可 xf
  • C# 获得窗体句柄并发送消息(利用windows API可在不同进程中获取)

    C 使用Windows API获取窗口句柄控制其他程序窗口 编写程序模拟鼠标和键盘操作可以方便的实现你需要的功能 xff0c 而不需要对方程序为你开放接口 比如 xff0c 操作飞信定时发送短信等 我之前开发过飞信耗子 xff0c 用的是对
  • c#中mysql远程连接方法及实例

    region 远程数据库连接测试 需给远程数据库分配所有权限 cmd命令 xff1a grant all privileges on to 39 root 39 64 39 39 with grant option string connS
  • mysql中数据库覆盖导入的几种方式

    众所周知 xff0c 数据库中INSERT INTO语法是append方式的插入 xff0c 而最近在处理一些客户数据导入场景时 xff0c 经常遇到需要覆盖式导入的情况 xff0c 常见的覆盖式导入主要有下面两种 xff1a 1 部分覆盖
  • mysql并发写入性能分析

    目前 xff0c 在很多OLTP场景中 xff0c MySQL数据库都有着广泛的应用 xff0c 也有很多不同的使用方式 从数据库的业务需求 架构设计 运营维护 再到扩容迁移 xff0c 不同的MySQL架构有不同的特点 xff0c 适应一
  • c#中的DefWndProc是Control类的虚函数

    protected override void DefWndProc ref Message m protected override void DefWndProc ref Message m 是Control的虚函数
  • C#使用Win32API获得窗口和控件的句柄

    整个Windows编程的基础 一个句柄是指使用的一个唯一的整数值 即一个4字节 64位程序中为8字节 长的数值 来标识应用程序中的不同对象和同类中的不同的实例 诸如 一个窗口 按钮 图标 滚动条 输出设备 控件或者文件等 应用程序能够通过句
  • C/C++新建注册表项实例

    使用Windows API 函数中的RegCreateKeyEx函数来实现对注册表新建注册表项 RegCreateKeyEx函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 原形 LONG RegCreateKeyEx
  • c#中通过win32API(FindWindowEx)查找控件句柄实例

    函数功能 该函数获得一个窗口的句柄 该窗口的类名和窗口名与给定的字符串相匹配 这个函数查找子窗口 从排在给定的子窗口后面的下 一个子窗口开始 在查找时不区分大小写 函数原型 HWND FindWindowEx HWND hwndParent
  • c#中使用消息循环机制发送接收字符串的方法和数据类型转换

    在定义消息时忘记了用户可定义消息的边界值 xff0c 在网上一阵疯找后来发现是const int WM USER 61 0x400 接着是SendMessage的lParam类型不能决定 xff08 默认是IntPtr xff09 xff0
  • C#WebApi路由机制详解

    随着前后端分离的大热 WebApi在项目中的作用也是越来越重要 可单独部署 与前端和App交互都很方便 既然有良好的发展趋势 我们当然应该顺势而为 搞懂WebApi Restful相当于给Http请求增加了语义 Post 增 Delete
  • xubuntu(ubuntu)重启后不能进入图形化界面

    问题描述 xff1a Xbuntu启动后进入了 VMware Easy Install视图 xff0c 不能进入图形化界面 问题思路 xff1a 在命令行模式下命令联想敲击时会报硬盘容量不足 xff0c 怀疑可能和硬盘大小相关 先尝试清理下
  • JSON数据格式详解

    文章目录 JSON数据格式概念 JSON的简单数据 JSON对象 对象的属性也可以是JSON对象 JSON格式表示简单数组 对象数组 使用二维数组保存 二维数组 访问淘宝的接口也可以取得JSON格式的数据 将一个对象转换成JSON数据 将一
  • C# 创建一个简单的WebApi项目

    一 创建Web API 1 创建一个新的web API项目 启动VS 2013 并在 开始页 选择 新项目 或从 文件 菜单选择 新建 然后选择 项目 在 模板 面板中选择 已安装模板 并展开 Visual C 节点 选择该节点下的 Web
  • C# 编写Web API

    1 创建Web API项目 打开VS2012 gt FILE gt New gt Project gt Web gt ASP NET MVC 4 Web Application 修改名字为WebAPIApplication 单击OK 在Pr

随机推荐

  • C# WebApi 返回JSON类型

    在默认情况下 当我们新建一个webapi项目 会自动返回XML格式的数据 如果我们想返回JSON的数据 可以设置下面的三种方法 nbsp 1 不用改配置文件 在Controller的方法中 直接返回HttpResponseMessage p
  • c#通过HttpClient来调用Web Api接口

    lt summary gt HttpClient实现Post请求 异步 lt summary gt static async void dooPost string url http localhost 52824 api register
  • c#使用HttpClient调用WebApi

    调用WebApi 可以利用HttpClient来进行Web Api的调用 由于WebA Api的调用本质上就是一次普通的发送请求与接收响应的过程 xff0c 所有HttpClient其实可以作为一般意义上发送HTTP请求的工具 using
  • C#中通过HttpClient发送Post请求

    C 中HttpClient进行各种类型的传输 我们可以看到 尽管PostAsync有四个重载函数 但是接受的都是HttpContent 而查看源码可以看到 HttpContent是一个抽象类 那我们就不可能直接创建HttpContent的实
  • c#中WepAPI(post/get)控制器方法创建和httpclient调用webAPI实例

    一 xff1a WebAPI创建 using System using System Collections Generic using System Linq using System Net Http using System Text
  • c#中Task线程的用法

    1 Task的优势 ThreadPool相比Thread来说具备了很多优势 xff0c 但是ThreadPool却又存在一些使用上的不方便 比如 xff1a ThreadPool不支持线程的取消 完成 失败通知等交互性操作 xff1b Th
  • C# 中对象与JSON字符串相互转换的三种方法

    JSON JavaScript Object Notation JS 对象标记 是一种轻量级的数据交换格式 关于内存对象和JSON字符串的相互转换 xff0c 在实际项目中应比较广泛 xff0c 经过一番搜索 xff0c 找到如下三种方法来
  • 解决VM虚拟机中ubuntu系统上不了网的问题

    最简单的方式 关闭虚拟机在对应的虚拟机上右键 xff0c 点击设置 xff0c 找到网络适配器 xff0c 点击移除 xff0c 再次点击添加 xff0c 将网络适配器再次添加回来 xff0c 点击确定重启虚拟机 如果第一种方式解决不了问题
  • C#中创建圆形/按钮(使用重绘)

    创建圆形按钮挺简单的 public class EllipseButton Button protected override void OnPaint PaintEventArgs pevent GraphicsPath gPath 61
  • c#中控件重绘(放大缩小移动隐藏恢复后不消失)实例

    很重要 一定要重写并在在OnPaint 中用传入的pevent Graphics重绘 并且屏蔽掉父类的OnPaint方法 这样重绘后的图形不论控件怎么操作都不会消失了 using System using System Collection
  • WM_Paint 消息疑问解析

    1 系统何时发送WM PAINT消息 xff1f 系统会在多个不同的时机发送 WM PAINT 消息 xff1a 当第一次创建一个窗口时 xff0c 当改变窗口的大小时 xff0c 当把窗口从另一个 窗口背后移出时 xff0c 当最大化或最
  • Windows 消息ID及定义大全

    表A 1 Windows消息分布 消息范围 说 明 0 xff5e WM USER 1 系统消息 WM USER xff5e 0x7FFF 自定义窗口类整数消息 WM APP xff5e 0xBFFF 应用程序自定义消息 0xC000 xf
  • C++中消息机制阻塞实验

    VC6标准WIN32程序 xff0c Windows消息处理机制 xff1a 1 在注册窗口类时 xff0c 指定了消息处理函数WndProc 2 WinMain xff08 xff09 里有消息循环 xff1a while GetMess
  • C#中控件如何设置透明色

    设置窗体的TransparencyKey 属性 xff0c 为你想要变成透明的颜色 xff0c 比如 xff1a 你把窗体背景色设置成红色 xff0c 然后把TransparencyKey 设置成红色 xff0c 代码 xff1a this
  • SendMessage消息发送原理与死锁处理

    windows是一个消息驱动的系统 xff0c 也是个多任务调度系统 xff0c windows中的线程分为两类 xff0c GUI线程与Worker线程 xff0c 每个GUI线程会关联消息队列 xff0c 当消息处理顺序不当时 xff0
  • C#中PostMessage和SendMessage的参数传递实例

    用 PostMessage SendNotifyMessage SendMessageCallback 等异步函数发送系统消息时 xff0c 参数里不可以使用指针 xff0c 因为发送者并不等待消息的处理就返回 xff0c 接受者还没处理指
  • WindowsAPI中PostMessage与SendMessage的区别

    xff11 返回值意义的区别 xff0c 先看一下 MSDN 里的声明 xff1a LRESULT SendMessage HWND hWnd UINT Msg WPARAM wParam LPARAM lParam BOOL PostMe
  • vnc viewer中文版,超好用的几款vnc viewer中文版

    现在 市面上有着各种各样的vnc viewer中文版软件 xff0c 在日常工作中 xff0c 也不可避免的会使用到vnc viewer中文版软件 毕竟对于我们国人来说 中文版软件更便于使用 你会选择哪一款vnc viewer中文版软件呢
  • c#基于socket的UDP服务器和客户端实例

    基于Udp协议是无连接模式通讯 xff0c 占用资源少 xff0c 响应速度快 xff0c 延时低 至于可靠性 xff0c 可通过应用层的控制来满足 不可靠连接 使用Udp协议通讯需要具备以下几个条件 xff1a 1 建立一个套接字 Soc
  • C# new和override的区别和用途

    override 1 override是派生类用来重写基类中方法的 xff1b 2 override不能重写非虚方法和静态方法 xff1b 3 override只能重写用virtual abstract override修饰的方法 xff1