C#中虚方法与隐藏方法的区别

前言:本博文讲解了C#中虚方法与隐藏方法的概念、定义以及区别。两者的细则之处,更是值得您反复推敲!

一、虚方法

1、概念讲解

在我们的C#编程中,把一个基类函数声明为virtual,这样我们就可以在它的任何派生类中重写该函数。同时,我们在其派生类中重写另外一个函数时,要使用override关键字显示声明。重写之后,原来的方法就不存在了。

2、示例讲解

  1. 首先,我们创建基类Person与派生类Student。并添加它俩相同的方法Run,我们设置基类Person的Run方法为虚函数,并让其派生类Student的Run方法进行重写。
class Person
{
    public virtual void Run()
    {
        Console.WriteLine("我是Person的成员方法,我可以跑~");
    }
}
class Student : Person
{
    public override void Run()
    {
        Console.WriteLine("我是Student的成员方法,我可以跑~");
    }
}
  1. 实例化一个学生stu1,调用它的Run方法。
Student stu1 = new Student();
stu1.Run();
  1. 执行结果,如下:
    在这里插入图片描述
  2. 我们改变上面的代码,看一下效果。
Student stu1 = new Student();
stu1.Run();
Person p1 = new Person();
p1.Run();
Person p2 = new Student();
p2.Run();
  1. 再次执行,结果如下:
    在这里插入图片描述

3、总结一下

我们在派生类里面重写虚函数之后,不管在哪里调用,只要是用派生类的构造函数实例化的对象,它都是调用重写之后的方法。但是如果我们调用的是基类构造的对象,此时它的派生类并没有重写虚方法,此时仍然调用基类的虚方法。

二、隐藏方法

1、概念讲解

如果签名相同的方法在基类和派生类中都进行了声明,但是该方法没有分别声明为virtualoverride,派生类就会隐藏基类方法(要使用new关键字进行声明)。隐藏的话,也就是看不到了,实际这个方法还存在。

2、案例讲解

  1. 和上面的案例一下,改动如下:
class Person
{
    public void Run()
    {
        Console.WriteLine("我是Person的成员方法,我可以跑~");
    }
}
class Student : Person
{
    public void Run()
    {
        Console.WriteLine("我是Student的成员方法,我可以跑~");
    }
}

注意:其派生类中的方法,new可写可不写,此时基类的方法为隐藏方法,如下:

public new void Run(){}
public void Run(){}
  1. 很明确,我们去掉了virtualoverride,此时这两个方法的签名完全相同,我们再用其派生类进行调用。
Student stu1 = new Student();
stu1.Run();
  1. 执行结果,如下:
    在这里插入图片描述
  2. 我们改变上面的代码,看一下会效果。
Student stu1 = new Student();
stu1.Run();
Person p1 = new Person();
p1.Run();
Person p2 = new Student();
p2.Run();
  1. 再次执行,结果如下:
    在这里插入图片描述

3、总结一下

如果使用派生类声明的对象,调用隐藏方法会调用派生类的,如果使用基类声明对象,那么就会调用基类的隐藏方法。

三、虚方法与隐藏方法的区别

1、重写和隐藏的定义

  1. 重写:继承时发生,在派生类中重新定义基类中的方法,派生类中的方法和基类的方法是一样的 。例如:基类方法声明为virtual(虚方法),派生类中使用override声明此方法的重写。

  2. 隐藏:基类方法不做声明(默认为非虚方法),在派生类中使用new声明此方法的隐藏(new可写可不写)。

2、重写和隐藏的区别

  1. 重写(virtaul)时,定义的变量为基类或派生类, 赋值为派生类时,皆调用基类的重写方法(会从派生类中查找有重写则调用 ,没则调用基类方法)。
  2. 隐藏(new)时,定义的变量为基类,则调用基类的方法(不管赋值是派生类还是基类),定义的变量为派生类则调用派生类的方法。
  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
第Ⅰ部分 C# 语 言 第1章 .NET体系结构.... 3 1.1 C#与.NET的关系...... 3 1.2 公共语言运行库...... 3 1.3 详细介绍间语言...... 6 1.3.1 面向对象和接口的支持..... 7 1.3.2 相异值类型和引用类型..... 8 1.3.3 强数据类型..... 8 1.3.4 通过异常方法处理错误..... 14 1.3.5 特性的使用..... 14 1.4 程序集...... 14 1.4.1 私有程序集..... 15 1.4.2 共享程序集..... 16 1.4.3 反射..... 16 1.5 .NET Framework类...... 16 1.6 命名空间...... 17 1.7 用C#创建.NET应用程序...... 18 1.7.1 创建ASP.NET应用程序..... 18 1.7.2 创建Windows窗体..... 20 1.7.3 Windows控件..... 20 1.7.4 Windows服务..... 20 1.8 C#在.NET企业体系结构 的作用...... 20 1.9 小结...... 22 第2章 C#基础.... 23 2.1 引言...... 23 2.2 第一个C#程序...... 23 2.2.1 代码..... 24 2.2.2 编译并运行程序..... 24 2.2.3 详细介绍..... 25 2.3 变量........ 27 2.3.1 变量的初始化..... 27 2.3.2 变量的作用域..... 28 2.3.3 常量..... 31 2.4 预定义数据类型...... 32 2.4.1 值类型和引用类型..... 32 2.4.2 CTS类型..... 33 2.4.3 预定义的值类型..... 33 2.4.4 预定义的引用类型..... 36 2.5 流控制...... 39 2.5.1 条件语句..... 39 2.5.2 循环..... 43 2.5.3 跳转语句..... 46 2.6 枚举...... 47 2.7 数组...... 49 2.8 命名空间...... 50 2.8.1 using语句..... 51 2.8.2 命名空间的别名..... 52 2.9 Main()方法...... 53 2.9.1 多个Main()方法..... 53 2.9.2 给Main()方法传送参数..... 54 2.10 有关编译C#文件的更多内容...... 55 2.11 控制台I/O.... 56 2.12 使用注释...... 58 2.12.1 源文件的内部注释..... 58 2.12.2 XML文档说明..... 59 2.13 C#预处理器指令...... 61 2.13.1 #define和 #undef. 61 2.13.2 #if, #elif, #else和#endif. 62 2.13.3 #warning和# error. 63 2.13.4 #region和#endregion.. 63 2.13.5 #line.. 64 2.13.6 #pragma.. 64 2.14 C#编程规则...... 64 2.14.1 用于标识符的规则..... 64 2.14.2 用法约定..... 65 2.15 小结...... 71 第3章 对象和类型.... 72 3.1 类和结构...... 72 3.2 类成员...... 73 3.2.1 数据成员..... 73 3.2.2 函数成员..... 74 3.2.3 只读字段..... 88 3.3 结构...... 89 3.3.1 结构是值类型..... 90 3.3.2 结构和继承..... 91 3.3.3 结构的构造函数..... 91 3.4 部分类...... 92 3.5 静态类...... 94 3.6 Object类...... 94 3.6.1 System.Object方法..... 94 3.6.2 ToString()方法..... 95 3.7 小结...... 97 第4章 继承.... 98 4.1 继承的类型...... 98 4.1.1 实现继承和接口继承..... 98 4.1.2 多重继承..... 99 4.1.3 结构和类..... 99 4.2 实现继承...... 99 4.2.1 虚方法..... 100 4.2.2 隐藏方法..... 101 4.2.3 调用函数的基类版本..... 102 4.2.4 抽象类和抽象函数..... 103 4.2.5 密封类和密封方法..... 103 4.2.6 派生类的构造函数..... 104 4.3 修饰符...... 109 4.3.1 可见性修饰符..... 109 4.3.2 其他修饰符..... 110 4.4 接口...... 111 4.4.1 定义和实现接口..... 112 4.4.2 派生的接口..... 116 4.5 小结...... 118 第5章 运算符和类型强制转换.... 119 5.1 运算符...... 119 5.1.1 运算符的简化操作..... 120 5.1.2 三元运算符..... 121 5.1.3 checked和unchecked运算符..... 122 5.1.4 is运算符..... 123 5.1.5 as运算符..... 123 5.1.6 sizeof运算符..... 123 5.1.7 typeof运算符..... 124 5.1.8 可空类型和运算符..... 124 5.1.9 空接合运算符..... 124 5.1.10 运算符的优先级..... 125 5.2 类型的安全性...... 125 5.2.1 类型转换..... 126 5.2.2 装箱和拆箱..... 130 5.3 对象的相等比较...... 130 5.3.1 引用类型的相等比较..... 131 5.3.2 值类型的相等比较..... 132 5.4 运算符重载...... 132 5.4.1 运算符的工作方式..... 133 5.4.2 运算符重载的示例: Vector结构..... 134 5.5 用户定义的数据类型转换...... 141 5.5.1 执行用户定义的类型转换..... 142 5.5.2 多重数据类型转换..... 149 5.6 小结...... 152 第6章 委托和事件.... 153 6.1 委托...... 153 6.1.1 在C#声明委托..... 154 6.1.2 在C#使用委托..... 155 6.2 匿名方法...... 158 6.2.1 简单的委托示例..... 159 6.2.2 BubbleSorter示例..... 161 6.2.3 多播委托..... 164 6.3 事件...... 166 6.3.1 从客户的角度讨论事件..... 167 6.3.2 生成事件..... 169 6.4 小结...... 173
内附1-19章的实战程序。 目录 第1章 c#语言及其开发环境 实例001 根据需要创建所需解决方案 实例002 统一窗体控件的字体设置 实例003 设置程序代码行号 实例004 通过“格式”菜单布局窗体 实例005 为项目添加dll文件引用 实例006 为项目添加已有类 实例007 为项目添加第三方控件 实例008 为项目添加已有窗体 第2章 c#语言基础 实例009 利用for循环输出多行语句 实例010 输入并输出姓名 实例011 使用值类型和引用类型输出不同的字段 实例012 判断当前系统日期是星期几 实例013 定义局部变量输出不同的字段 实例014 定义循环内部变量并输出变量的值 实例015 定义常量计算圆的周长 实例016 使用“+”编写双重意义的表达式 实例017 使用小括号括起来的表达式 实例018 使用算术运算符开发简单计算器 实例019 使用条件运算符判断指定年份是不是闰年 实例020 使用typeof关键字获取类的内部结构 实例021 巧用位移运算符获取汉字编码值 实例022 使用异或运算符对数字进行加密 第3章 流程控制语句 实例023 利用if…else语句判断分数是否及格 实例024 利用switch语句判断时间 实例025 利用while语句判断大小 实例026 打印九九乘法表 实例027 使用break语句提前退出循环语句 实例028 使用continue语句转移至循环开始处 实例029 使用流程控制语句报销业务花销 实例030 输出当前系统时间 实例031 利用for循环实现完数计算 实例032 开发一个猜数字游戏 第4章 字符与字符串 实例033 字母与ascii码的转换 实例034 获取字符串汉字的个数 实例035 从字符串分离文件路径、文件名及扩展名 实例036 对字符串进行加密与解密 实例037 开发一个进制转换器 实例038 将字符串的每个字符进行颠倒输出 实例039 根据标点符号对字符串进行分行 实例040 将汉字转换为拼音 实例041 商品金额的大小写转换 实例042 根据年份判断十二生肖 实例043 将字母全部转换为大写或小写 实例044 汉字与区位码的转换 第5章 数组和集合 实例045 在数组添加一个元素 实例046 在数组添加一个数组 实例047 计算两个矩形矩阵的乘积 实例048 获取多维数组的行数与列数 实例049 使用快速排序法对一维数组进行排序 实例050 使用sort方法对数组进行快速排序 实例051 按指定条件在数组检索元素 实例052 反转数组元素的顺序 实例053 使用希尔排序法对一维数组进行排序 实例054 向班级集合添加学生信息 实例055 不改变长度删除数组的元素 实例056 删除数组元素后改变其长度 第6章 c#面向对象程序设计 实例057 创建类的对象 实例058 使用构造函数 实例059 通过定义方法求一个数的平方 实例060 使用重载方法实现不同类型数据的计算 实例061 使用属性存储用户编号和姓名 实例062 使用索引器 实例063 通过类继承计算梯形面积 实例064 封装类实现一个简单的计算器 实例065 通过结构计算矩形的面积 实例066 通过结构计算圆形的面积 实例067 使用面向对象思想查找字符串的所有数字 实例068 通过类的多态性确定人类的说话行为 第7章 异常处理和程序调试 实例069 使用try…catch语句捕获异常 实例070 根据实际年龄判断虚岁,使用try…catch捕获异常 实例071 调试程序执行时出现的结果 实例072 使用异常处理语句捕获异常 实例073 捕获连接数据库异常 第8章 windows窗体 实例074 简单的登录窗体 实例075 关闭窗体提示 实例076 创建简单的mdi应用程序 实例077 实现重复高效地利用基窗体 实例078 尝试制作一个半透明渐显窗体 实例079 使窗体标题栏文字右对齐 实例080 窗口间移动按钮 实例081 窗体滚动的字幕 实例082 使用任意组件拖动窗体 实例083 窗体换肤程序 第9章 windows应用程序常用控件 实例084 在c#设计出色彩斑斓的按钮 实例085 自动删除textbox控件的非法字符 实例086 在richtextbox控件替换文本文字 实例087 利用richtextbox控件实现文字定位与标示 实例088 将数据表的字段添加到combobox控件 实例089 对listbox控件的数据进行排序 实例090 listbox控件拒绝添加重复信息 实例091 限制用户名称长度及设置密码文本 实例092 带查询功能的combobox控件 实例093 利用选择控件实现权限设置 实例094 利用richtextbox控件显示图文数据 实例095 在listbox控件间交换数据 第10章 windows应用程序高级控件 实例096 使用imagelist组件制作动画图片 实例097 在combobox下拉列表显示图片 实例098 在listview控件实现修改功能 实例099 将数据库数据添加到listview控件 实例100 在listview控件绘制底纹 实例101 在treeview控件节点显示图片 实例102 使用树型列表动态显示菜单 实例103 使用treeview控件遍历磁盘目录 实例104 使用errorprovider组件验证文本框输入 实例105 使用helpprovider组件调用帮助文件 实例106 使listview控件的选择项高亮显示 实例107 在列表视图拖动视图项 实例108 实现带复选框的treeview控件 实例109 将xml文件节点绑定到treeview控件 实例110 修改treeview控件的节点文本 第11章 c#面向对象高级技术 实例111 利用接口实现选择不同的语言 实例112 使用接口作为方法参数进行编程 实例113 自定义抽象类计算圆形的面积 实例114 重写抽象方法实现多态性 实例115 使用密封类密封登录用户信息 实例116 使用密封类封装个人身份证信息 实例117 使用迭代器显示公交车站点 实例118 通过迭代器实现文字的动态效果 实例119 使用分部类制作一个计算器 实例120 使用分部类显示员工信息 实例121 使用泛型存储不同类型的数据列表 实例122 使用泛型去掉数组的重复数字 实例123 通过重写虚方法实现加法运算 实例124 使用迭代器实现倒序遍历 实例125 通过泛型查找数组的元素 第12章 ado.net数据访问技术 实例126 连接加密的access数据库 实例127 使用odbc dsn连接sql server数据库 实例128 使用ado.net对象录入数据 实例129 利用存储过程录入数据 实例130 使用oledbdatareader读取文本文件的内容 实例131 使用sqldatareader读取用户登录信息 实例132 使用断开式连接的方式录入数据 实例133 使用断开式连接批量更新数据库的数据 实例134 使datagridview控件被选定单元格的所在行变色 实例135 在datagridview控件隔行换色 实例136 连接excel文件 实例137 读取和保存用户头像 实例138 判断是否重复输入数据 实例139 删除datagridview控件的指定行 实例140 将access数据库导入excel文件 第13章 水晶报表与打印 实例141 设计带有背景图的水晶报表 实例142 设置水晶报表的打印日期与时间 实例143 设置水晶报表节的背景图片 实例144 打印窗体的数据 实例145 打印商品入库单据 实例146 使用打印控件实现分页打印 实例147 动态绑定水晶报表 实例148 在水晶报表使用公式字段 实例149 设计分组统计报表 实例150 打印一个空学生证 实例151 自定义横向或纵向打印 实例152 自定义打印页码范围 第14章 文件及数据流技术 实例153 根据日期动态建立文件 实例154 将长文件名转换成短文件名 实例155 获取所有逻辑磁盘目录 实例156 使用递归法删除文件夹的所有文件 实例157 按行读取文本文件的数据 实例158 使用缓冲流复制文件 实例159 文件批量更名 实例160 复制文件时显示复制进度 实例161 对指定文件夹的文件进行分类存储 实例162 将文本文件转换成网页文件 实例163 伪装文件夹 实例164 word目录提取工具 第15章 gdi+绘图 实例165 在图像实现自定义标记 实例166 辉光效果的文字 实例167 渐变效果的文字 实例168 绘制多边形 实例169 简单画图程序 实例170 仿qq截图功能 实例171 模拟石英钟 实例172 绘制贝塞尔曲线 实例173 绘制图形验证码 实例174 以椭圆形显示图像 实例175 使用双缓冲技术绘图 实例176 批量添加图片水印 第16章 线程的使用 实例177 使用线程读取数据库的数据 实例178 使用线程制作qq农场小游戏 实例179 使用线程实现大容量数据的计算 实例180 使用多线程制作端口扫描工具 实例181 使用线程扫描局域网ip地址 实例182 使用线程休眠控制图片以百叶窗效果显示 实例183 使用线程控制向窗体拖放图片并显示 实例184 使用线程制作动画效果的状态栏 实例185 使用线程遍历文件夹 实例186 使用线程实现从左向右以拉伸的方式显示图像 第17章 网络编程技术 实例187 通过ip地址获取主机名称 实例188 创建web页面浏览器 实例189 获取网络信息及流量 实例190 远程关闭与重启计算机 实例191 设计点对点聊天程序 实例192 电子邮件的发送与接收 实例193 获取网络所有工作组名称 实例194 列出指定工作组的所有计算机名 实例195 监测当前网络连接状态 实例196 使用udp协议设计聊天室 第18章 注册表技术 实例197 禁止运行注册表 实例198 使应用程序开机自动运行 实例199 获取本机安装的软件清单 实例200 禁止使用windows任务管理器 实例201 清除ie地址栏的历史网址 实例202 将磁盘驱动器隐藏 实例203 禁止使用命令提示符 实例204 禁止修改ie浏览器主页 实例205 设置ie浏览器的默认主页 实例206 设置ie浏览器的默认下载路径 第19章 c#语言新技术 实例207 使用隐式类型局部变量实现字母的大小写转换 实例208 使用扩展方法显示员工信息 实例209 使用lambda表达式查找指定字符串 实例210 检查序列是否包含指定元素 实例211 使用linq在一个循环遍历多个数组 实例212 过滤文章包含指定单词的句子 实例213 使用linq生成随机序列 实例214 筛选指定类型的元素 实例215 使用linq技术对对象进行筛选操作 实例216 使用linq技术对对象进行排序操作 实例217 使用linq技术对对象进行聚合操作 实例218 使用linq技术对对象进行联接操作 第20章 windows应用程序打包部署 实例219 打包程序时设置桌面图标 实例220 打包.net framework 4.0框架
C#虚方法和抽象方法都是实现多态性的重要手段,它们的区别在于抽象方法必须在派生类被重写并提供具体的实现,而虚方法则可以在派生类被重写也可以不被重写。下面是两者的具体介绍: 1. 虚方法(Virtual Methods): 虚方法是指在基类声明并提供默认实现的方法,它可以在派生类被重写。通过使用关键字"virtual",可以标记一个方法虚方法虚方法在基类可以包含方法体,也可以不包含方法体。如果在派生类重写了虚方法,那么在派生类对象上调用该方法时,实际调用的是派生类的重写方法。 下面是一个虚方法的例子: ```csharp class Shape { public virtual void Draw() { Console.WriteLine("Drawing a shape"); } } class Circle : Shape { public override void Draw() { Console.WriteLine("Drawing a circle"); } } class Square : Shape { // 不重写基类虚方法 } class Program { static void Main(string[] args) { Shape s1 = new Circle(); Shape s2 = new Square(); s1.Draw(); // 输出:Drawing a circle s2.Draw(); // 输出:Drawing a shape } } ``` 2. 抽象方法(Abstract Methods): 抽象方法是指在基类声明但没有提供实现的方法。抽象方法必须在派生类被重写并提供具体的实现。通过使用关键字"abstract",可以标记一个方法为抽象方法。抽象方法在基类只能进行声明,不能包含方法体。 下面是一个抽象方法的例子: ```csharp abstract class Shape { public abstract void Draw(); } class Circle : Shape { public override void Draw() { Console.WriteLine("Drawing a circle"); } } class Square : Shape { public override void Draw() { Console.WriteLine("Drawing a square"); } } class Program { static void Main(string[] args) { Shape s1 = new Circle(); Shape s2 = new Square(); s1.Draw(); // 输出:Drawing a circle s2.Draw(); // 输出:Drawing a square } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值