C# 最基础知识介绍–多态

C# 最基础知识介绍--多态

在C#中,多态是面向对象编程(OOP)中的常见概念,它允许不同类型的对象对相同的消息作出响应。简单地说,多态就是对象(或方法)有不同的表现形式。

多态性有三种形式:静态,动态和协变。下面我们会一一解释。

静态多态

静态多态性是在编译时确定的,在程序执行之前,就确定了发生的方法和参数。在编程语言C#中,静态多态性可以通过函数重载和运算符重载实现。每个函数都必须有一个唯一的名字,并且参数的数量和类型必须不同,但是在编译时确定。

以函数重载为例,假设我们有以下两个函数定义,分别实现了对数值的平方和对字符串的拼接操作。

static int Square(int n)
{
    return n * n;
}

static string Concat(string s1, string s2)
{
    return s1 + s2;
}

我们可以看到,这两个函数的名称都是不同的,他们可以同时存在于同一个程序中。

同时,由于函数的参数类型和数量不同,使得函数的调用必须显式地指明参数类型,所以编译器知道调用哪个函数。

int result = Square(3);
string str = Concat("hello", "world");

动态多态

动态多态性是在程序运行时确定的,使用基类声明的指针或引用可以指向派生类的对象。这里主要涉及到继承和虚函数的使用。

例如:

class Shape
{
    public virtual double Area()
    {
        return 0;
    }
}

class Circle : Shape
{
    double radius;

    public Circle(double r)
    {
        radius = r;
    }

    public override double Area()
    {
        return 3.14 * radius * radius;
    }
}

class Rectangle : Shape
{
    double length;
    double width;

    public Rectangle(double l, double w)
    {
        length = l;
        width = w;
    }

    public override double Area()
    {
        return length * width;
    }
}

在上面的代码示例中,我们定义了一个基类 Shape 和两个继承类 CircleRectangle。同时,Shape 中定义了一个虚函数 Area(),派生类可以覆盖这个方法来实现不同的功能。重点是在声明的时候使用了关键字 virtual 和继承类中重写的关键字 override

现在,我们可以通过基类的引用调用覆盖之后的方法,这里就是通过定义 Shape 类型的变量来指向两个派生类的实例,实现了运行时的多态性。

Shape shape1 = new Circle(3);
Shape shape2 = new Rectangle(4, 5);

double area1 = shape1.Area();
double area2 = shape2.Area();

协变

协变允许派生类的方法返回基类的对象。换句话说,协变可以将派生类作为基类来使用。

例如:

interface ICovariant<out T>
{
    T Get();
}

class Animal { }
class Cat : Animal { }

class CovariantCat : ICovariant<Cat>
{
    public Cat Get()
    {
        return new Cat();
    }
}

class CovariantAnimal : ICovariant<Animal>
{
    public Animal Get()
    {
        return new Animal();
    }
}

在上面的代码示例中,我们定义了一个协变接口 ICovariant<T>,其中 out 关键字表示协变。然后定义了两个派生类 CovariantCatCovariantAnimal,显然 CovariantCat 中的 Get() 方法返回的是 Cat 类型的对象,而 CovariantAnimal 中的 Get() 方法返回的是 Animal 类型的对象,但是由于使用了协变,这个方法也可以将派生类的实例也返回给基类。

ICovariant<Animal> animal = new CovariantCat();
Animal animalObj = animal.Get();

在这个示例中,我们将 CovariantCat 类型的对象赋值给 ICovariant<Animal> 类型的变量。此时,使用 Get() 方法从接口中获取的对象仍然是 Cat 类型,但是编译器会将它转换成 Animal 对象,以允许将派生类对象作为基类来使用。

示例说明

下面举两个具体的例子来说明多态的使用方法。

示例一:吃饭

class Animal
{
    public virtual void Eat()
    {
        Console.WriteLine("动物在吃...");
    }
}

class Cat : Animal
{
    public override void Eat()
    {
        Console.WriteLine("猫在吃鱼...");
    }
}

class Dog : Animal
{
    public override void Eat()
    {
        Console.WriteLine("狗在吃肉...");
    }
}

在上面的代码中,我们定义了一个抽象的 Animal 类,然后 CatDog 类都继承自 Animal 类。同时,Animal 类中定义了一个 Eat() 方法。CatDog 类都重写了 Eat() 方法。

然后我们可以创建一个 List<Animal> 来表示动物园中的动物们,然后调用它们的 Eat() 方法。

List<Animal> animals = new List<Animal>();
animals.Add(new Cat());
animals.Add(new Dog());

foreach (Animal animal in animals)
{
    animal.Eat();
}

输出结果如下:

猫在吃鱼...
狗在吃肉...

我们可以看到,由于 CatDog 类重写了 Eat() 方法,调用 List<Animal> 类型的对象的 Eat() 方法时,会根据实际执行的对象来调用对应的方法。这种由对象的实际类型来决定方法的调用方式,就是运行时多态。

示例二:图形面积计算

abstract class Shape
{
    public abstract double Area();
}

class Circle : Shape
{
    double radius;

    public Circle(double r)
    {
        radius = r;
    }

    public override double Area()
    {
        return 3.14 * radius * radius;
    }
}

class Rectangle : Shape
{
    double length;
    double width;

    public Rectangle(double l, double w)
    {
        length = l;
        width = w;
    }

    public override double Area()
    {
        return length * width;
    }
}

在上面的代码中,我们定义了一个抽象的 Shape 类,然后 CircleRectangle 类都继承自 Shape 类。同时,Shape 类中定义了一个抽象的 Area() 方法。CircleRectangle 类都实现了这个方法。

然后我们可以创建一个 List<Shape> 来表示各种形状的图形,然后计算它们的面积。

List<Shape> shapes = new List<Shape>();
shapes.Add(new Circle(3));
shapes.Add(new Rectangle(4, 5));

foreach (Shape shape in shapes)
{
    Console.WriteLine("面积是:" + shape.Area());
}

输出结果如下:

面积是:28.26
面积是:20

我们可以看到,由于 CircleRectangle 类都实现了 Area() 方法,调用 List<Shape> 类型的对象的 Area() 方法时,会根据实际执行的对象来调用对应的方法。这种由对象的实际类型来决定方法的调用方式,也是运行时多态。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C# 最基础知识介绍–多态 - Python技术站

(0)
上一篇 2023年6月1日
下一篇 2023年6月1日

相关文章

  • 区分c# 前台和后台线程

    要区分C#前台和后台线程,主要是要理解它们之间的区别以及相应的使用场景。以下是区分C#前台和后台线程的完整攻略: 什么是前台线程和后台线程 前台线程 前台线程是指在应用程序的主线程中创建的线程,这些线程会阻止应用程序的终止,只有在所有前台线程执行完成后应用程序才会退出。 后台线程 后台线程是指在应用程序中创建的没有阻止应用程序终止的线程,当所有前台线程都执行…

    C# 2023年6月7日
    00
  • asp.net中生成缩略图并添加版权实例代码

    你需要掌握以下内容: 通过使用 System.Drawing 命名空间,将图片文件读入 Bitmap 对象。 创建一个新的 Bitmap 对象,调用 Graphics 对象将原始图片画到新的 Bitmap 对象上,并指定新的大小。 通过 Image.Save 方法将缩略图保存为新的文件。 添加版权信息。 下面是示例代码和详细步骤: 1. 通过使用 Syste…

    C# 2023年5月31日
    00
  • 关于C#委托三种调用的分享使用

    关于C#委托的三种调用方式,分别是:直接调用、使用BeginInvoke/EndInvoke方法异步调用、使用线程池异步调用。下面逐一进行详细讲解。 直接调用 直接调用是指在委托实例后面直接加上小括号和对应参数,就相当于调用了委托所指向的方法。示例代码如下: using System; namespace DelegateDemo { class Progr…

    C# 2023年6月7日
    00
  • 流量统计器如何鉴别C#:WebBrowser中伪造referer

    要理解流量统计器如何鉴别C#: WebBrowser中伪造referer,需要先了解什么是referer。 Referer通常指HTTP请求头中的Referer(即引用),它是由HTTP客户端(例如网页浏览器)发送的一种HTTP Headers。它表示了客户端是从哪个URL提交请求的。这个Header让Web浏览器和服务器能够更好地进行访问分析、日志记录、反…

    C# 2023年6月6日
    00
  • abp(net core)+easyui+efcore实现仓储管理系统——模块管理升级(六十)

    Abp(net core)+easyui+efcore实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统——ABP总体介绍(一) abp(net core)+easyui+efcore实现仓储管理系统——解决方案介绍(二) abp(net core)+easyui+efcore实现仓储管理系统——领域层创建实体(三)…

    C# 2023年4月18日
    00
  • c#入门之循环语句使用详解(for循环、do/while)

    C#入门之循环语句使用详解(for循环、do/while) 引言 在编写程序的过程中,经常需要对某些语句进行重复的执行,这时候就需要使用循环语句。本文将详细讲解C#中for循环和do/while循环的使用。 for循环 for循环是最基本的循环语句之一,在C#中也有完整的语法: for (initialization; condition; incremen…

    C# 2023年5月31日
    00
  • c# 类型的字段和方法设计建议

    下面来详细讲解 “c# 类型的字段和方法设计建议” 的完整攻略。 1. 建议在字段中使用自动属性 在定义类型的字段时,可以使用自动属性来简化代码。自动属性与传统的字段定义不同,后者需要定义字段和访问器方法(Getter/Setter),而自动属性可以在定义字段时直接定义 Getter 和 Setter 方法。举个例子: public class Person…

    C# 2023年6月1日
    00
  • ASP.NET MVC把数据库中枚举项的数字转换成文字

    以下是“ASP.NET MVC把数据库中枚举项的数字转换成文字”的完整攻略: 什么是枚举 枚举是一种特殊的数据类型,它定义了一组命名的常量。在.NET MVC中,枚举通常用于表示状态、类型等。 ASP.NET MVC把数据库中枚举项的数字转换成文字的过程 以下ASP.NET MVC把数据库中枚举项的数字转换成文字的详细过程: 步骤1:定义枚举 首先,我们需要…

    C# 2023年5月12日
    00
合作推广
合作推广
分享本页
返回顶部