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# 解决IIS写Excel的权限问题

    针对这个问题,我们需要先明确一下背景和原理。 背景 通常情况下,在我们开发 ASP.NET 程序时,会遇到需要生成 Excel 文件的情况。而在将 Excel 文件写入到服务器磁盘时,可能会面临权限不足的问题,导致写入失败。那么如何解决这个问题呢? 原理 在 IIS 中,每个应用程序池都有一个对应的身份标识,这个身份标识默认是 IIS AppPool{应用程…

    C# 2023年5月15日
    00
  • C# 中string.split用法详解

    下面是关于”C#中string.split用法详解”的完整攻略: 1. split方法的作用 split方法是用于将字符串分割成字符串数组的方法。可以使用指定的分隔符对字符串进行拆分,获取到拆分后的各个子字符串。拆分后的子字符串将存储在一个字符串数组中,数组元素的个数就是拆分后子字符串的数量。 2. split方法的语法 下面是split方法的语法: pub…

    C# 2023年6月8日
    00
  • 解析C#多线程编程中异步多线程的实现及线程池的使用

    解析C#多线程编程中异步多线程的实现及线程池的使用 什么是多线程? 多线程是指程序中同时执行多个线程,可以让应用程序同时执行多项任务,提高程序运行效率和用户体验。在C#中,可以使用Thread类或Task类来创建多线程应用。 什么是异步多线程? 异步多线程是指可以让应用程序在执行某个操作时不被阻塞,同时可以继续执行其他操作。在C#中,可以使用async和aw…

    C# 2023年5月15日
    00
  • c#实现winform屏幕截图并保存的示例

    下面是 “c#实现winform屏幕截图并保存的示例”的完整攻略。 1. 前置知识 在进行本次实验之前,请确保你已经掌握以下内容: C#语言基础知识 Winform应用程序开发和控件使用 .NET Framework中Graphics和Bitmap类的使用 2. 实现屏幕截图的代码 下面是一个简单的C#程序,利用Graphics和Bitmap类从当前屏幕中截…

    C# 2023年6月6日
    00
  • c# 数据标注与数据校验

    以下是“c# 数据标注与数据校验”的完整攻略: 什么是数据标注与数据校验 在C#中,数据标注和数据校验是用来确保输入数据的有效性的两个重要概念。数据标注可以将各种标记应用于数据,使得我们可以在数据类中定义该数据的元数据。而数据校验可以帮助保证数据符合特定的规则和限制条件,从而消除了由错误数据引起的问题。 数据标注详解 什么是数据标注 数据标注是一种将标记应用…

    C# 2023年5月31日
    00
  • ASP.NET Core 6框架揭秘实例演示之如何承载你的后台服务

    ASP.NET Core 6框架揭秘实例演示之如何承载你的后台服务 在本攻略中,我们将详细讲解如何使用ASP.NET Core 6框架承载你的后台服务。我们将介绍ASP.NET Core 6框架的基础知识、如何创建和承载后台服务的步骤以及两个示例说明。 ASP.NET Core 6框架基础知识 ASP.NET Core 6框架是一个跨平台的开源框架,用于构建…

    C# 2023年5月17日
    00
  • C#正则表达式实用大全(建议收藏!)

    C#正则表达式实用大全(建议收藏!) 什么是正则表达式? 正则表达式是一种文本模式,通常被用来检索、替换那些符合某个模式的文本。在C#中,我们可以使用正则表达式来进行字符串匹配、查找和替换等操作。 正则表达式的语法 在C#中,正则表达式语法使用的是Perl风格的语法,它包含了很多元字符和修饰符,可以用来匹配常见的文本模式。下面是一些常用的正则表达式元字符: …

    C# 2023年6月1日
    00
  • C#实现刷新桌面的方法

    下面是“C#实现刷新桌面的方法”的完整攻略。 标题 介绍 在Windows系统中,桌面通常是我们经常使用的界面之一。有时候我们需要在程序中通过代码控制桌面的刷新,例如动态修改桌面背景等。本攻略将介绍如何通过C#代码实现刷新桌面的方法。 方法 在C#中,可以通过发送一条特定的消息显式地强制Windows桌面刷新。具体实现步骤如下: 步骤1 在代码中引入下列命名…

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