学习c#的第十三天

news2024/11/15 13:32:30

目录

C# 多态性

静态多态性

函数重载

运算符重载

动态多态性

virtual 和 abstract

抽象方法和虚方法的区别

重载(overload)和重写(override)

隐藏方法


C# 多态性

多态是同一个行为具有多个不同表现形式或形态的能力。

多态性意味着有多重形式。在面向对象编程范式中,多态性往往表现为"一个接口,多个功能"。

多态性可以是静态的或动态的。在静态多态性中,函数的响应是在编译时发生的。在动态多态性中,函数的响应是在运行时发生的。

在 C# 中,每个类型都是多态的,因为包括用户定义类型在内的所有类型都继承自 Object。

多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:

现实中,比如我们按下 F1 键这个动作:

  • 如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;
  • 如果当前在 Word 下弹出的就是 Word 帮助;
  • 在 Windows 下弹出的就是 Windows 帮助和支持。

同一个事件发生在不同的对象上会产生不同的结果。

静态多态性

在编译时,函数和对象的连接机制被称为早期绑定,也被称为静态绑定。C# 提供了两种技术来实现静态多态性。分别为:

函数重载

在C#中,函数重载指的是在同一个类中可以定义多个具有相同名称但参数列表不同的函数。通过函数重载,可以根据不同的参数列表来调用合适的函数。

下面是一个简单的示例,演示了如何在C#中使用函数重载:

using System;

public class DateUtils
{
    // 函数重载
    public string FormatDate(DateTime dt)
    {
        return dt.ToString("yyyy/MM/dd HH:mm:ss.fff");
    }

    public string FormatDate(DateTime dt, string format)
    {
        return dt.ToString(format);
    }
}

public class Program
{
    public static void Main()
    {
        DateUtils utils = new DateUtils();

        DateTime now = DateTime.Now;

        // 使用不同的重载函数进行日期格式化
        string formattedDate1 = utils.FormatDate(now); // 使用第一个重载函数
        string formattedDate2 = utils.FormatDate(now, "yyyy-MM-dd HH:mm:ss"); // 使用第二个重载函数

        // 输出格式化后的日期
        Console.WriteLine("格式化日期1: " + formattedDate1);
        Console.WriteLine("格式化日期2: " + formattedDate2);
    }
}

在上面的示例中,DateUtils 类中定义了两个名为 FormatDate 的函数。第一个函数接受一个 DateTime 类型的参数,并将日期格式化为特定的格式。第二个函数接受一个 DateTime 类型的参数和一个表示日期格式的字符串参数,并根据传入的格式对日期进行格式化。这两个函数拥有相同的名称但参数列表不同。

运算符重载

C#允许我们重定义或重载内置运算符,以便在用户自定义类型上使用它们。运算符重载通过关键字operator后面跟着运算符的符号来定义。

下面是一些常见的运算符重载的示例:

1、算术运算符:

  • +:重载为public static T operator +(T operand1, T operand2)
  • -:重载为public static T operator -(T operand1, T operand2)
  • *:重载为public static T operator *(T operand1, T operand2)
  • /:重载为public static T operator /(T operand1, T operand2)
  • %:重载为public static T operator %(T operand1, T operand2)

2、比较运算符:

  • ==:重载为public static bool operator ==(T operand1, T operand2)
  • !=:重载为public static bool operator !=(T operand1, T operand2)
  • <:重载为public static bool operator <(T operand1, T operand2)
  • >:重载为public static bool operator >(T operand1, T operand2)
  • <=:重载为public static bool operator <=(T operand1, T operand2)
  • >=:重载为public static bool operator >=(T operand1, T operand2)

3、逻辑运算符:

  • !:重载为public static bool operator !(T operand)
  • &:重载为public static bool operator &(T operand1, T operand2)
  • |:重载为public static bool operator |(T operand1, T operand2)

4、位运算符:

  • ~:重载为public static T operator ~(T operand)
  • &:重载为public static T operator &(T operand1, T operand2)
  • |:重载为public static T operator |(T operand1, T operand2)
  • ^:重载为public static T operator ^(T operand1, T operand2)

5、赋值运算符:

  • =:重载为public static void operator =(T destination, T source)
  • +=:重载为public static T operator +=(T operand1, T operand2)
  • -=:重载为public static T operator -=(T operand1, T operand2)
  • *=:重载为public static T operator *=(T operand1, T operand2)
  • /=:重载为public static T operator /=(T operand1, T operand2)
  • %=:重载为public static T operator %=(T operand1, T operand2)

这些示例只是一些常见的运算符重载示例,你可以根据自己的需求重载其他运算符。需要注意的是,并非所有运算符都可以被重载,具体可重载的运算符列表请参考C#官方文档。

代码示例

using System;

public class Complex
{
    public double Real { get; set; }
    public double Imaginary { get; set; }

    public Complex(double real, double imaginary)
    {
        Real = real;
        Imaginary = imaginary;
    }

    // 重载加法运算符 "+"
    public static Complex operator +(Complex c1, Complex c2)
    {
        return new Complex(c1.Real + c2.Real, c1.Imaginary + c2.Imaginary);
    }

    // 重载减法运算符 "-"
    public static Complex operator -(Complex c1, Complex c2)
    {
        return new Complex(c1.Real - c2.Real, c1.Imaginary - c2.Imaginary);
    }

    // 重载乘法运算符 "*"
    public static Complex operator *(Complex c1, Complex c2)
    {
        double real = c1.Real * c2.Real - c1.Imaginary * c2.Imaginary;
        double imaginary = c1.Real * c2.Imaginary + c1.Imaginary * c2.Real;
        return new Complex(real, imaginary);
    }

    // 重载复数的输出格式
    public override string ToString()
    {
        return $"{Real} + {Imaginary}i";
    }
}

class Program
{
    static void Main()
    {
        Complex c1 = new Complex(1, 2);
        Complex c2 = new Complex(3, 4);

        Complex sum = c1 + c2; // 使用重载的加法运算符
        Console.WriteLine($"总和: {sum}");

        Complex difference = c1 - c2; // 使用重载的减法运算符
        Console.WriteLine($"差别: {difference}");

        Complex product = c1 * c2; // 使用重载的乘法运算符
        Console.WriteLine($"相乘: {product}");
    }
}

当上面的代码被编译和执行时,它会产生下列结果:

总和: 4 + 6i
差别: -2 + -2i
相乘: -5 + 10i

动态多态性

在C#中,使用抽象类和虚方法可以实现动态多态性。

C# 允许您使用关键字 abstract 创建抽象类,用于提供接口的部分类的实现。当一个派生类继承自该抽象类时,实现即完成。抽象类包含抽象方法,抽象方法可被派生类实现。派生类具有更专业的功能。

请注意,下面是有关抽象类的一些规则:

  • 抽象类不能被实例化,只能被用作其他类的基类。
  • 抽象类中可以包含抽象方法,这些方法没有具体的实现,而是由派生类来实现。
  • 通过在类定义前面放置关键字 sealed,可以将类声明为密封类。当一个类被声明为 sealed 时,它不能被继承。抽象类不能被声明为 sealed。

下面的程序演示了一个抽象类:

using System;

// 定义抽象类
public abstract class Shape
{
    public string Name { get; set; }

    // 定义抽象方法
    public abstract double CalculateArea();
}

// 继承自抽象类的具体类:圆形
public class Circle : Shape
{
    public double Radius { get; set; }

    // 实现抽象方法
    public override double CalculateArea()
    {
        return Math.PI * Radius * Radius;
    }
}

// 继承自抽象类的具体类:正方形
public class Square : Shape
{
    public double SideLength { get; set; }

    // 实现抽象方法
    public override double CalculateArea()
    {
        return SideLength * SideLength;
    }
}

class Program
{
    static void Main()
    {
        Circle circle = new Circle { Name = "圆形", Radius = 3 };
        Console.WriteLine("圆形的面积: " + circle.CalculateArea());  // 输出结果:"圆形的面积: 28.274333882308138"

        Square square = new Square { Name = "正方形", SideLength = 4 };
        Console.WriteLine("正方形的面积: " + square.CalculateArea());  // 输出结果:"正方形的面积: 16"
    }
}

 另外,虚方法是在基类中,可以使用关键字virtual来声明一个方法为虚方法,表示它可以被派生类重写。而在派生类中,可以使用关键字override来重写基类中的虚方法。

通过使用抽象类和虚方法,可以实现代码的可扩展性和灵活性。抽象类提供了一种统一的接口,定义了需要实现的方法,而具体的实现则由派生类来完成。虚方法允许在派生类中重写方法,实现不同的行为。

以下是一个简单的代码示例,演示了如何使用抽象类和虚方法来实现动态多态性。

using System;

// 定义一个抽象类
public abstract class Shape
{
    // 定义一个虚方法
    public virtual double CalculateArea()
    {
        return 0;
    }
}

// 派生类1:矩形
public class Rectangle : Shape
{
    public double Width { get; set; }
    public double Height { get; set; }

    // 实现抽象方法
    public override double CalculateArea()
    {
        return Width * Height;
    }
}

// 派生类2:圆形
public class Circle : Shape
{
    public double Radius { get; set; }

    // 实现抽象方法
    public override double CalculateArea()
    {
        return Math.PI * Radius * Radius;
    }
}

class Program
{
    static void Main()
    {
        // 创建一个矩形对象
        Shape rect = new Rectangle { Width = 5, Height = 10 };
        Console.WriteLine("矩形的面积:" + rect.CalculateArea());

        // 创建一个圆形对象
        Shape circle = new Circle { Radius = 3 };
        Console.WriteLine("圆形的面积:" + circle.CalculateArea());
    }
}

当上面的代码被编译和执行时,它会产生下列结果:

矩形的面积:50
圆形的面积:28.274333882308138

virtual 和 abstract

  • virtual关键字用于修饰方法,表示该方法在基类中有一个默认实现,但派生类可以选择性地重写它。通常情况下,virtual方法会提供一个默认实现,但可以在派生类中进行修改或扩展。即使派生类没有重写virtual方法,它仍然会使用基类中的默认实现。
  • abstract关键字用于修饰方法或类,表示它们没有具体的实现。抽象方法只有定义,没有实现,派生类必须重写它们,并且提供具体的实现。抽象类本身也不能被实例化,只能作为基类被其他类继承。

需要注意的是,抽象方法只能存在于抽象类中,而不是普通的类。如果一个类包含抽象方法,则该类本身必须被声明为抽象类。而虚方法可以存在于任何类中,无论是抽象类还是普通类。

总之,virtual和abstract关键字都用于实现多态性,在派生类中重新定义父类的方法。virtual方法允许派生类选择重写并提供新的实现,而abstract方法则要求派生类必须提供具体的实现。另外,抽象类本身不能被实例化,只能作为其他类的基类使用。

抽象方法和虚方法的区别

  1. 抽象方法(abstract method)必须在抽象类中声明,并且没有具体的实现部分。派生类必须重写并提供具体的实现,否则派生类将无法被实例化。
  2. 虚方法(virtual method)在基类中有一个默认的实现,但也可以在派生类中进行重写。派生类可以选择性地覆盖虚方法,或者直接使用基类的默认实现。
  3. 抽象方法和虚方法都可以供派生类重写以定制化行为,但抽象方法必须在派生类中进行重写,而虚方法可以选择性地进行重写。

重载(overload)和重写(override)

1、重载(overload): 在同一个作用域(一般指一个类)的两个或多个方法函数名相同,参数列表不同的方法叫做重载,它们有三个特点(俗称两必须一可以):

  •  方法名必须相同
  •  参数列表必须不相同
  •  返回值类型可以不相同

2、重写(override):子类中为满足自己的需要来重复定义某个方法的不同实现,需要用 override 关键字,被重写的方法必须是虚方法,用的是 virtual 关键字。它的特点是(三个相同):

  • 相同的方法名
  • 相同的参数列表
  • 相同的返回值

代码示例

using System;

public class Calculator
{
    // 方法重载,参数列表不同
    public int Add(int num1, int num2)
    {
        return num1 + num2;
    }

    public double Add(double num1, double num2)
    {
        return num1 + num2;
    }
}

public class Shape
{
    // 虚方法
    public virtual void Draw()
    {
        Console.WriteLine("正在绘制形状。。。");
    }
}

public class Circle : Shape
{
    // 重写基类的虚方法
    public override void Draw()
    {
        Console.WriteLine("正在绘制圆。。。");
    }
}

class Program
{
    static void Main()
    {
        Calculator calculator = new Calculator();
        int result1 = calculator.Add(3, 4);              // 调用第一个Add方法
        double result2 = calculator.Add(2.5, 3.7);       // 调用第二个Add方法

        Console.WriteLine("int加法的结果: " + result1); // 输出结果:"int加法的结果: 7"
        Console.WriteLine("double加法的结果: " + result2); // 输出结果:"double加法的结果: 6.2"

        Shape shape1 = new Shape();
        shape1.Draw();         // 输出结果:"正在绘制形状。。。"

        Shape shape2 = new Circle();
        shape2.Draw();         // 输出结果:"正在绘制圆。。。"
    }
}

隐藏方法

当在派生类中定义一个与基类中同名的方法时,会发生方法隐藏。使用关键字 new 可以实现方法隐藏。

using System;

public class Shape
{
    public void Draw()
    {
        Console.WriteLine("正在绘制形状。。。");
    }
}

public class Circle : Shape
{
    public new void Draw()
    {
        Console.WriteLine("正在绘制圆。。。");
    }
}

class Program
{
    static void Main()
    {
        Shape shape1 = new Shape();
        shape1.Draw();         // 输出结果:"正在绘制形状。。。"

        Shape shape2 = new Circle();
        shape2.Draw();         // 输出结果:"正在绘制形状。。。"(调用的是基类的方法)

        Circle circle = new Circle();
        circle.Draw();         // 输出结果:"正在绘制圆。。。"
    }
}

在上述代码中,Shape 类定义了一个 Draw() 方法,Circle 类继承自 Shape 并定义了一个同名的 Draw() 方法并使用 new 关键字进行方法隐藏。

在 Main() 方法中,首先创建了一个 Shape 对象 shape1,调用其 Draw() 方法,输出结果为 "正在绘制形状。。。"。接着创建了一个 Circle 对象 shape2,将其赋值给 Shape 类型的变量 shape2,再次调用 shape2.Draw() 方法,输出结果仍然为 ""正在绘制形状。。。"",这是因为变量的静态类型是 Shape,所以调用的是基类的方法。最后,创建了一个 Circle 对象 circle,直接调用其 Draw() 方法,输出结果为 "正在绘制圆。。。",这是因为直接通过派生类的实例调用方法时,会调用派生类中隐藏的方法。

需要注意的是,方法隐藏并不是方法重写。如果想要实现方法的多态性,应该使用方法重写(override)而不是隐藏(new)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1212101.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

自由曲线与曲面 -计算机图形学

目录 自由曲线与曲面 函数的连续性 &#xff08;1&#xff09;参数连续性 &#xff08;2&#xff09;几何连续性 bezier 曲线 Bernstein基函数 *公式看不懂&#xff0c;带几个数进去看看&#xff0c;你就更好地可以看到这个公式的本质了 凸包性质 仿射不变性 …

PyCharm 【unsupported Python 3.1】

PyCharm2020.1版本&#xff0c;当添加虚拟环境发生异常&#xff1a; 原因&#xff1a;Pycharm版本低了&#xff01;不支持配置的虚拟环境版本 解决&#xff1a;下载PyCharm2021.1版本&#xff0c;进行配置成功&#xff01;

mysql之搭建MMM架构实现高可用

实验目的 解决mysql的主从服务器单点故障问题&#xff0c;实现高可用 实验思路 实验条件&#xff1a; 主机名 作用 IP地址 组件 mysql1 master01 20.0.0.13 mysql服务、mysql-mmm mysql2 masert02 20.0.0.23 mysql服务、mysql-mmm mysql3 slave01 20.0.0.33 …

C# 使用Microsoft.Office.Interop.Excel库操作Excel

1.在NuGet管理包中搜索&#xff1a;Microsoft.Office.Interop.Excel&#xff0c;如下图红色标记处所示&#xff0c;进行安装 2. 安装完成后&#xff0c;在程序中引入命名空间如下所示&#xff1a; using Microsoft.Office.Interop.Excel; //第一步 添加excel第三方库 usi…

kubernetes集群编排——prometheus监控

部署prometheus 创建项目仓库并上传镜像 编写配置文件 [rootk8s2 values]# vim prometheus-values.yaml alertmanager:alertmanagerSpec:image:repository: prometheus/alertmanagertag: v0.24.0 grafana:enabled: trueimage:repository: grafana/grafanatag: 9.0.6service:typ…

【开发问题解决方法记录】01.dian

一些问题记录 新增角色失败&#xff1a;Error: Ajax 调用为Execute Server-Side Code返回了服务器错误ORA-01722: 无效数字。 【问题原因】&#xff1a;CREATE_BY(NUMBER类型)应该存入USER_ID(NUMBER类型)而非USER_NAME&#xff08;NVARCHAR2类型&#xff09; 【解决方法】将…

一篇文章让你真正搞懂epoll机制

目录 1.epoll简介 2.epoll实现原理 3.创建epoll文件 4.增加&#xff0c;删除&#xff0c;修改epoll事件 5.epoll事件就绪 6.epoll编程流程 7.epoll常见问题&#xff1f; 1.epoll简介 epoll是Linux内核为处理大批量文件描述符而作了改进的poll&#xff0c;它能显著提高程…

一篇文章让你搞懂 MySQL 的锁

一篇文章让你搞懂 MySQL 的锁 1、并发问题的解决方案2、MySQL的各类型锁2.1、从数据操作的类型划分 (读锁、写锁)2.2、从数据操作的粒度划分2.2.1、表锁2.2.1.1、表级别的S 锁、X 锁2.2.1.2、意向锁&#xff08;IS、IX&#xff09;2.2.1.3、自增锁2.2.1.4、元数据锁 2.2.2、行锁…

亚马逊收到CPSC查验通知后卖家需要怎么弄?ASTM F963标准测试 ,CPC认证

收到CPSC查验亚马逊卖家需要怎么做&#xff1f; 。CPSC消费品安全协会&#xff0c;成立于1972年&#xff0c;它的责任是保护广大消费者的利益&#xff0c;通过减少消费品存在的伤害及死亡的危险来维护人身及家庭安全。CPSC现在负责对超过15000种消费品的安全监控&#xff0c;具…

【送书福利-第二十七期】《边缘计算系统设计与实践》

&#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主、前后端开发、人工智能研究生。公粽号&#xff1a;程序员洲洲。 &#x1f388; 本文专栏&#xff1a;本文…

基于Genio 700 (MT8390)芯片的AR智能眼镜方案

AR眼镜是一种具有前所未有发展机遇的设备&#xff0c;无论是显示效果、体积还是功能都有明显的提升。AR技术因其智能、实时、三维、多重交互和开放世界的特点备受关注。 AR眼镜集成了AR技术、语音识别、智能控制等多项高科技功能&#xff0c;可以帮助用户实现更加便捷、高效、个…

电脑桌面任务提醒便签选择哪一个好用?

伴随着科技现代化的发展&#xff0c;电脑成为大家日常办公及生活中必不可少的工具&#xff0c;如在日常办公中大家可以借助电脑上的任务提醒便签来合理规划自己的工作时间&#xff0c;督促任务的完成&#xff0c;提高工作的效率。 当前&#xff0c;支持在电脑上安装的任务提醒…

RGB转Bayer,一个小数点引发的血案

前几天写了一个RGB数据转Bayer格式的函数&#xff0c;经过测试功能正常。后来把这个函数用到一个数据库构建中&#xff0c;结果数据库出来的结果一直是一张黑图&#xff0c;追查了好几个小时&#xff0c;总算把这只虫子找出来了&#xff0c;原来是一个整数后面的小数点作祟。 …

基础课4——客服中心管理者面临的挑战

客服管理者在当今的数字化时代也面临着许多挑战。以下是一些主要的挑战&#xff1a; 同行业竞争加剧&#xff1a;客服行业面临着来自同行业的竞争压力。为了获得竞争优势&#xff0c;企业需要不断提高自身的产品和服务质量&#xff0c;同时还需要不断降低成本、提高效率。然而…

热烈庆祝瑞森半导体成立10周年

瑞森半导体10年芯路&#xff0c;衷心感谢全球合作伙伴、 客户、员工、朋友的帮助与支持。 弹指一挥间&#xff0c;瑞森半导体已在功率半导体行业奋勇前行了十年。3650个白天与黑夜&#xff0c;瑞森半导体在风雨兼程中砥砺前行&#xff0c;在倾情奉献中不负初心。十年里有太多的…

Go ZIP压缩文件读写操作

创建zip文件 golang提供了archive/zip包来处理zip压缩文件&#xff0c;下面通过一个简单的示例来展示golang如何创建zip压缩文件&#xff1a; func createZip(filename string) {// 缓存压缩文件内容buf : new(bytes.Buffer)// 创建zipwriter : zip.NewWriter(buf)defer writ…

如何高效收集数据?

在当今这个信息爆炸的时代&#xff0c;数据已经成为了一种新的资源&#xff0c;其价值不可估量。收集数据的重要性日益凸显&#xff0c;无论是对于企业、政府还是个人&#xff0c;数据都已经成为了一种宝贵的财富。分享一些网站。 一、宏观数据 1.国家统计局&#xff08;数据…

智慧工地综合管理平台-项目开发管理规范

目的 本规范制定旨在规范项目的开发流程,提高软件开发质量和效率,降低开发成本和风险。该规范包括但不限于以下几个方面: 项目管理 包括项目计划、需求分析、设计、开发、测试、发布等环节,以及项目进度、质量和风险管理等方面项目计划管理:制定项目计划,包括确定项目目…

基于Springboot+Vue的社区医院管理系统

基于SpringbootVue的社区医院管理系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 医生列表 医生详情 登录界面 管理员界面 医生界面 摘要 社区医院管…

day22_mysql

今日内容 零、 复习昨日 一、MySQL 一、约束 1.1 约束 是什么? 约束,即限制,就是通过设置约束,可以限制对数据表数据的插入,删除,更新 怎么做? 约束设置的语法,大部分是 create table 表名( 字段 数据类型(长度) 约束, 字段 数据类型(长度) 约束 );1.1 数据类型 其实数据类型…