服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - C#子类对基类方法的继承、重写与隐藏详解

C#子类对基类方法的继承、重写与隐藏详解

2022-09-29 16:14老胡写代码 C#

这篇文章主要介绍了C#子类对基类方法的继承、重写与隐藏的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者使用C#具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

前言

提起子类、基类和方法继承这些概念,肯定大家都非常熟悉。毕竟,作为一门支持OOP的语言,掌握子类、基类是学习C#的基础。不过,这些概念虽然简单,但是也有一些初学者可能会遇到的坑,我们一起看看吧。

子类继承基类非私有方法

首先我们看最简单的一种,子类继承自基类,但子类对继承的方法没有任何改动

class Person
{
public void Greeting()
{
Console.WriteLine("Hello, I am Person");
}
}

class Employee : Person
{

}

class Program
{
static void Main(string[] args)
{
Person p = new Employee();
p.Greeting();
}
}

在这个例子中,作为子类的Employee自动继承了基类的Greeting方法,当在子类实例调用这个方法的时候,实际上调用的是基类的方法。这个例子非常简单,毋庸多言。

子类覆盖基类方法

接着是最常见的情况,子类覆盖基类的方法,典型的例子如下

class Person
{
public virtual void Greeting()
{
Console.WriteLine("Hello, I am Person");
}
}

class Employee : Person
{
public override void Greeting()
{
Console.WriteLine("Hello, I am Employee");
}
}

class Program
{
	static void Main(string[] args)
	{
		Employee e = new Employee();
		Person p = e;
		p.Greeting();
		e.Greeting();
	}
}

同样,这段代码也很简单,基类方法通过关键字virtual表明方法可以被覆盖,子类通过关键字override实现对基类方法的覆盖,最后看调用部分,无论变量类型是子类还是基类,只要对象实际类型是子类,调用的方法都是子类覆盖的方法,这也是多态的实现基础。

子类隐藏基类方法

上面两个例子都非常简单,逻辑也很清楚,有点绕的要算子类隐藏基类方法的情况。

子类隐藏基类的非虚方法

基类被子类继承的方法可能是虚方法,也可能是非虚方法,先看非虚方法被子类隐藏的情况,隐藏基类方法使用的关键字是new

class Person
{
public void Greeting()
{
Console.WriteLine("Hello, I am Person");
}
}

class Employee : Person
{
public new void Greeting()
{
Console.WriteLine("Hello, I am Employee");
}
}

class Program
{
static void Main(string[] args)
{
Employee e = new Employee();
Person p = e;
p.Greeting();
e.Greeting();
}
}

C#子类对基类方法的继承、重写与隐藏详解

这里的结果可能就出乎某些初学者的意料了,为什么明明是子类Employee的实例,却在不同的引用变量类型下呈现出了不一样的效果?为什么会调用到了基类里面的方法?
其实这跟C#的函数调用机制有关,一般来说,C#编译成MSIL之后,有两种函数调用方式。

  • Call 以非虚的方式调用方法,一般用于静态函数调用,因为静态函数不可能是虚的,但也可以以非虚的方式调用一个虚方法
  • Callvirt 以虚方式调用,一般用于非静态方法和虚方法的调用。如果调用的方法非虚,则引用变量类型决定了最终调用的方法;反之,如果调用的方法为虚,则实例变量类型决定最终调用的方法——因为可能出现方法重写,即,多态

用ILDASM打开我们的程序集看看,

C#子类对基类方法的继承、重写与隐藏详解

证明了这里确实是用的Callvirt,而这个方法是非虚的方法,所以在两次调用中,引用变量类型Person和Employee就能够决定所调用的方法。两个类分别实现了自己的Greeting方法,没有出现子类覆盖基类方法的情况。这就解释了为什么两次调用结果不同。最后让我们来看看最复杂的一种情况

子类隐藏基类的虚方法

考虑下面的代码

class Person
{
public virtual void Greeting()
{
Console.WriteLine("Hello, I am Person");
}
}

class Employee : Person
{
public new virtual void Greeting()
{
Console.WriteLine("Hello, I am Employee");
}
}

class Manager : Employee
{
public override void Greeting()
{
Console.WriteLine("Hello, I am Manager");
}
}

class Program
{
static void Main(string[] args)
{
Manager m = new Manager();
Person p = m;
Employee e = m;
p.Greeting();
e.Greeting();
m.Greeting();
}
}

猜一下输出应该是什么?这也是老胡曾经遇到过的一道笔试题,表面看着简单,但是不注意也会掉坑里

1,2,3,答案揭晓

C#子类对基类方法的继承、重写与隐藏详解

是不是有点出乎意料呢,让我们来分析一下

C#子类对基类方法的继承、重写与隐藏详解

首先,三次调用均是callvirt,而且方法Greeting是虚方法,我们需要考虑对象实例以决定要调用的方法。

  • 在第一次调用中,引用变量类型是Person,虽然对象实例类型Manger重写了Greeting方法,但是它重写的是继承自Manger基类Emplyee的Greeting方法,Person中Greeting方法在子类Manger中仅仅是被隐藏而没有被重写,所以这里调用的是Person中的Greeting
  • 而第二次调用中,引用变量类型是Employee,Employee的Greeting方法被Manager重写,所以这次调用到的是Manager中的Greeting
  • 最后一次调用毋庸多言,简单的重写案例而已

怎么样,是不是有小伙伴猜错结果了?

总结

在子类对基类有方法继承、重写和隐藏的情况下,有时候判断具体哪个方法被调用会有难度,但请记住以下要点:

如果被调用方法非虚,那么只用关注引用变量类型就好,引用变量类型能决定调用方法在哪里如果调用方法为虚,我们需要站在引用变量类型的角度,审视该方法是否被对象类型所重写;若是,则调用对象类型的重写方法;反之,则再次让引用变量类型决定调用方法。

这样,当我们再遇到子类隐藏基类虚方法的情况,应用以上要点就可以拨云见日。

到此这篇关于C#子类对基类方法的继承、重写与隐藏的文章就介绍到这了,更多相关C#子类对基类方法继承、重写与隐藏内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://www.cnblogs.com/deatharthas/p/13378708.html

延伸 · 阅读

精彩推荐
  • C#C# 表达式树Expression Trees的知识梳理

    C# 表达式树Expression Trees的知识梳理

    本篇文章主要介绍了表达式树 Expression Trees的基础知识:Lambda 表达式创建表达式树;API 创建表达式树;编译表达式树;执行表达式树;修改表达式树等等,...

    反骨仔(二五仔)9452021-12-16
  • C#C#图片处理3种高级应用

    C#图片处理3种高级应用

    本文介绍C#图片处理高级应用,这些功能并无多大技术含量。全部基于.Net Framework类库完成,代码中包含了C#图片处理的一些基础知识,与大家分享,个人能...

    吴剑11392021-10-29
  • C#解析错误富文本json字符串(带双引号)的快速解决方法

    解析错误富文本json字符串(带双引号)的快速解决方法

    下面小编就为大家带来一篇解析错误富文本json字符串(带双引号)的快速解决方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小...

    C#教程网5542021-12-02
  • C#C#实现飞行棋项目

    C#实现飞行棋项目

    这篇文章主要为大家详细介绍了C#实现飞行棋项目,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    氪金万岁~11022022-08-24
  • C#C#中TCP粘包问题的解决方法

    C#中TCP粘包问题的解决方法

    这篇文章主要为大家详细介绍了C#中TCP粘包问题的解决方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    白云随风5722022-01-17
  • C#C# 数组中的 indexOf 方法及使用

    C# 数组中的 indexOf 方法及使用

    这篇文章主要介绍了C# 数组中的 indexOf 方法以及indexof方法的使用讲解,需要的朋友可以参考下...

    艹逆风飞翔丶灬沫5152022-02-20
  • C#深入理解C# 7.0中的Tuple特性

    深入理解C# 7.0中的Tuple特性

    这篇文章主要介绍了C#7中Tuple特性的相关资料,文中通过示例代码介绍的非常详细,相信对大家具有一定的参考价值,需要的朋友可以们下面来一起学习学...

    Tony9422021-12-30
  • C#在C#的类或结构中重写ToString方法的用法简介

    在C#的类或结构中重写ToString方法的用法简介

    这篇文章主要介绍了在C#的类或结构中重写ToString方法的用法简介,需要的朋友可以参考下...

    C#教程网8642021-11-09