C#基础之面向对象编程(二)

news2024/11/25 15:58:52

总目录


文章目录

  • 总目录
  • 前言
  • 一、概述
    • 1. 定义
    • 2. 面向对象的三大特性
  • 二、封装
    • 1. 定义
    • 2. 属性
  • 三、继承
    • 1. 定义
    • 2. 继承的使用
    • 3. base 和this
  • 四、多态
    • 1. 定义
    • 2. 重写和重载
    • 3. 多态性的实现
      • 1、静态多态性
      • 2、动态多态性
    • 4. 向上转型和向下转型
      • 1、定义
      • 2、语法格式
      • 3、案例
  • 结语


前言

本文主要用于供自身复习使用,上篇文章首先回顾了C#中的数据类型,数据转换以及数据之间进行运算的运算符,然后回顾了基本的流程控制语句if else,switch for,while等,最后还回顾了数组,枚举,结构体,类,接口,抽象类等基本的数据结构,本文将从面向对象编程的角度进一步的回顾相关知识。


一、概述

1. 定义

把现实世界中的对象使用代码的形式表现出来

2. 面向对象的三大特性

  • 封装 - 体现了代码的可维护性
  • 继承 - 体现了代码的可扩展性
  • 多态 - 体现了代码的灵活性

二、封装

1. 定义

  • 封装 被定义为"把一个或多个项目封闭在一个物理的或者逻辑的包中"。
  • 在面向对象程序设计方法论中,封装是为了防止对实现细节的访问。
  • 通俗说法:使用class,将变量和方法,包装到一个独立的程序单元中,一旦封装后,变量称之为属性,方法称为行为

2. 属性

变量封装到类中,分为两种形式:
字段:变量的声明,使用_标识
属性:使用get 和set 进行包装,一般首字母大写,符合驼峰命名规则

代码如下(示例):

    class UserInfo
    {
        private string _id;
        public string Id
        {
            get { return _id; }
            set { _id = value; }
        }
    }

关于get 和set 的理解如下:

 		private int _id;
        public int Id
        {
            get//返回给外界的值,供外界调用读取的值  
            {
                if (_id < 0)//如果内部逻辑得出的_id<0,则同一返回0
                {
                    _id = 0;
                }
                return _id; 
            }
            set//供给外界设置的窗口,如果设置为private,外界将无法为该属性赋值,为只读属性
            {
                if (value>999)//value 即是外界赋予的值,可以通过set来处理外界的值
                {
                    _id = 999;//如果外界赋予的值大于999,则统一修正为999
                }
                _id = value;
            }
        }

三、继承

1. 定义

  • 一个类通过申明沿用另一个类中,非私有的属性和行为。
  • 被继承的类称之为 基类或父类,继承类称之为 派生类或子类

继承的可扩展性体现在:继承的时候,子类不仅沿用父类中非私有的属性和行为,还可增加自己特有的内容,另外通过重写和重载,同样实现了内容的扩展

注意 : 继承的时候,一个类只能有一个父类

2. 继承的使用

继承我们通过冒号(:)表示,表现形式如下:

class Shape
   {
      public void setWidth(int w)
      {
         width = w;
      }
      public void setHeight(int h)
      {
         height = h;
      }
      protected int width;
      protected int height;
   }

   // 派生类
   class Rectangle: Shape
   {
   	  //通过 Rectangle: Shape 的形式表示:Rectangle继承自Shape 
   	  //由于Rectangle继承自Shape,就有了Shape中非私有的width和height变量以及setWidth和setHeight
      public int getArea()
      {
         return (width * height);
      }
   }
   
   class RectangleTester
   {
      static void Main(string[] args)
      {
         Rectangle Rect = new Rectangle();

         Rect.setWidth(5);
         Rect.setHeight(7);

         // 打印对象的面积
         Console.WriteLine("总面积: {0}",  Rect.getArea());
         Console.ReadKey();
      }
   }

3. base 和this

  • 一般当前类使用this,子类使用父类的使用base
  • 构造函数时不可继承的 ,只能去调用;因此子类使用父类的构造函数的时候,需要使用base

在这里插入图片描述

  • 子类继承了父类的非私有的属性和行为,因此子类使用父类的非私有属性和行为的时候使用this
  • 子类调用父类的方法,可使用base,也可使用this。主要是使用base的时候我们知道去父类找该方法,指向更明确
  • 大多情况下,都省略的this和base关键字

四、多态

1. 定义

  • 在面向对象编程范式中,多态性往往表现为"一个接口,多个功能"。
    多态就是同一个接口,使用不同的实例而执行不同操作,如图所示
    在这里插入图片描述

2. 重写和重载

重写:在子类中重新编写父类方法

重写具有相同的方法名、参数列表以及返回值

重写的方式有如下两种:

  • 使用new 重写(也称覆盖)
  • 使用vitual 和override 重写
    class Animal
    {
        public void Eat()
        {
            Console.WriteLine("吃");
        }

        //定义虚方法,需子类重新,另外abstract 自带virtual属性
        public virtual void Action()
        {
            Console.WriteLine("行动");
        }
    }

    class Monkey:Animal
    {
        //通过new 重写父类的方法
        public new void Eat()
        {
            Console.WriteLine("猴子吃香蕉");
        }

        //通过override重写
        public override void Action()
        {
            base.Action();//重写后,可以通过base调出父类的原方法执行,也可不调用,重新实现
            Console.WriteLine("猴子上树");
        }
    }

重载:就是在同一个类中有多个同名方法,但是方法的参数列表不同

重载可以实现一种方法的多种实现方式,有利于程序的扩展。

    class Animal
    {
        public void Eat()
        {
            Console.WriteLine("吃");
        }

        public void Eat(string food)
        {
            Console.WriteLine($"吃{food}");
        }

        public void Eat(int num,string food)
        {
            Console.WriteLine($"一天吃{num}{food}");
        }

        public int Eat(string name ,int num,string food)
        {
            Console.WriteLine($"{name}一天吃{num}{food}");
            //如猴子一天吃三次香蕉,(假如一次2根),返回一天总量
            return num * 2 ;
        }
    }

3. 多态性的实现

  • 多态性可以是静态的或动态的。
  • 在静态多态性中,函数的响应是在编译时发生的。
  • 在动态多态性中,函数的响应是在运行时发生的。
  • 多态是建立在封装和继承的基础上的

1、静态多态性

静态多态性通过函数(方法)重载和运算符重载实现。
函数重载上面已经介绍了,这里介绍以下运算符的重载。

C# 允许用户定义的类型通过使用 operator 关键字定义静态成员函数来重载运算符。
注意必须用public修饰且必须是类的静态的方法。

运算符的重载可为用户自定义的对象实现运算。

运算符重载的使用案例如下:

    class Rect
    {
        public double Width { get; set; }
        public double Length { get; set; }

        public static Rect operator+(Rect a,Rect b)
        {
            Rect rect = new Rect();
            rect.Width = a.Width + b.Width;
            rect.Length = a.Length + b.Length;
            return rect;
        }

        public double GetArea()
        {
            return Width * Length;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Rect RectA = new Rect() { Width=2.5,Length=4};
            Rect RectB = new Rect() { Width=3.5,Length=6};
            Console.WriteLine($"RectA的面积{RectA.GetArea()}");
            Console.WriteLine($"RectB的面积{RectB.GetArea()}");

            //如果没有通过operator+ 进行重载,RecA是无法和RecB进行相加的操作的
            Rect RectC = RectA+RectB;
            Console.WriteLine($"RectC的面积{RectC.GetArea()}");

            Console.ReadLine();
        }
    }

下图罗列了可重载和不可重载的运算符
在这里插入图片描述
这里解释以下成对重载,也就是说,如果我们重载了==,那么就必须连同 != 一起重载

详细使用如下:

    class Program
    {
        static void Main(string[] args)
        {
            Student student = new Student(15, "小栗子");
            var student1 = student + 3;
            var student2 = student + "新手小白";
            Console.WriteLine(student1.ToString());//年龄 = 18,名称 = 小栗子

            Console.WriteLine(student2.ToString());//年龄 = 15,名称 = 新手小白小栗子

            Student stu1 = new Student(12, "小张子");
            Student stu2 = new Student(18, "小王五");
            var stu3 = stu1 - stu2;
            Console.WriteLine(stu3.ToString()); //年龄 = 6,名称 = 小张子和小王五
            Console.ReadLine();
        }
    }

    public class Student
    {
        public int Age { get; set; }
        public string Name { get; set; }

        public Student()
        { }

        public Student(int age, string name)
        {
            this.Age = age;
            this.Name = name;
        }
        # 形如 public static Student operator +(int c1, int c2) 是会报错的
        # 因为这样,就与需要操作的Student类毫无关联!
        # 二元运算符的参数之一必须是包含类型(参数c1、c2中有一个类型为Student即可).
        
        //+重载 ,操作年龄
        public static Student operator +(Student stu, int c2)
        {
            return new Student(stu.Age + c2, stu.Name);
        }
        //+重载 ,增加姓名前缀
        public static Student operator +(Student stu, string prefix)
        {
            return new Student(stu.Age, prefix+stu.Name); 
        }

        //重载运算符"-",计算两个学生的年龄差.
        public static Student operator -(Student a, Student b)
        {
            return new Student(Math.Abs(a.Age - b.Age), $"{a.Name}{b.Name}");
        }

        //重写ToString方法,格式化输出
        public override string ToString()
        {
            return $"年龄={Age},名称={Name}";
        }
    }

2、动态多态性

动态多态性是通过 抽象类、接口 和 虚方法 实现的。

  • 抽象类 和 接口 综合案例如下:
    abstract class Animal
    {
       public abstract void Run();//abstract 自带virtual属性
    }

    interface IFly//接口默认public,通常接口命名以 I 开头
    {
        void Fly();//飞翔这项功能作为一个接口,并不是所有动物都可以的
    }

    class Monkey : Animal
    {
        public override void Run()
        {
            Console.WriteLine("猴子在奔跑!");
        }
    }

    class Pig : Animal
    {
        public override void Run()
        {
            Console.WriteLine("小猪在狂奔!");
        }
    }
    //同一个方法(“接口”)Run,在不同的实例中有不同的实现就是多态的一种体现


    # 这里需要注意:当一个子类同时继承抽象类,类,和接口的时候,抽象类,类必须排在接口前面

    class Brid : Animal, IFly
    {
        public void Fly()
        {
            Console.WriteLine("奋飞的小鸟!");
        }

        public override void Run()
        {
            Console.WriteLine("愤怒的小鸡在奔跑!");
        }
    }
  • 虚方法
    class Worker
    {
        public virtual void DoWork()
        {
            Console.WriteLine("做工作!");
        }
    }

    class WorkerA : Worker
    {
        public override void DoWork()
        {
            base.DoWork();
            Console.WriteLine("编写项目ppt");
        }
    }

4. 向上转型和向下转型

1、定义

  • 向上转型:将子类对象转为父类对象。此处父类对象可以是接口,抽象类。
  • 向下转型:把父类对象转为子类对象。
  • 向上转型和向下转型 就是针对同一个继承链中的两个类型的相互转换

2、语法格式

  • 向上转型格式:父类类型 上转型变量 = new 子类类型();
  • 向下转型格式:子类类型 下转型变量 = (子类类型)父类类型变量;

3、案例

    class Worker
    {
        public virtual void DoWork()
        {
            Console.WriteLine("做工作!");
        }
    }

    class WorkerA : Worker
    {
        public override void DoWork()
        {
            base.DoWork();
            Console.WriteLine("编写项目ppt");
        }

        public void Avocation()
        {
            Console.WriteLine("WorkA的业余爱好");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            //向上转型
            Worker worker= new WorkerA();
            worker.DoWork();
            /*  输出:
                做工作!
                编写项目ppt
             */

            //worker.Avocation();
            //注意这里会报错:因为上转型变量不是可调用 子类中扩展的方法的,只能调用两者共有的方法


            //向下转型
            //这种情况是不合理的,因为相当于用父类替换子类,当时子类会有扩展,不可能完全替换
            //Worker wo = new Worker();
            //WorkerA wa = (WorkerA)wo;

            Worker wo = new WorkerA();
            WorkerA wa = (WorkerA)wo;
            wa.Avocation();//这样是可行的,因为自始至终实例都是WorkA
            wo.DoWork();

            /*
             WorkA的业余爱好
             做工作!
             编写项目ppt
             */
            Console.ReadLine();
        }
    }

结语

以上就是本文的内容,希望以上内容可以帮助到您,如文中有不对之处,还请批评指正。


参考资料:
C# 运算符重载
菜鸟教程-C# 运算符重载

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

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

相关文章

Docker常用项目实战演练

docker镜像源的修改 linux环境下编辑 /etc/docker/daemon.json vi /etc/docker/daemon.json #如添加如下网易镜像源 { "registry-mirrors": ["http://hub-mirror.c.163.com"] }docker run命令详细解释 日常工作中用的比较多的是docker run命令&#xff…

[ROC-RK3399-PC Pro] 手把手教你移植主线Buildroot(基于2023.02-rc3版本)

&#x1f347; 博主主页&#xff1a;Systemcall小酒屋&#x1f347; 博主简介&#xff1a;Neutionwei&#xff0c;C站嵌入式领域新星创作者之一&#xff0c;一枚热爱开源技术、喜欢分享技术心得的极客&#xff0c;注重简约风格&#xff0c;热衷于用简单的案例讲述复杂的技术&am…

机械学习 - 基础概念 - scikit-learn - 数据预处理 - 1

目录安装 scikit-learn术语理解1. 特征&#xff08;feature &#xff09;和样本&#xff08; sample / demo&#xff09;的区别&#xff1f;2. 关于模型的概念一、机械学习概念1. 监督学习总结&#xff1a;2. 非监督学习总结&#xff1a;3. 强化学习总结&#xff1a;三种学习的…

硬件基础常识【1】--如何让BJT工作在深度饱和区

引言BJT饱和的概念差不多的比喻特性曲线说明记忆NPN和PNP的小技巧- -保证一辈子不忘简单估算总结引言 学过模电或者做过一些电子作品的人都知道三极管这个器件&#xff0c;虽然是个小玩意&#xff0c;但在电路设计过程中承担了巨大的作用。BJT叫做双极结型三极管&#xff0c;可…

浏览器并发行为记录

使用nodejs koa起一个服务&#xff0c;使请求延时返回。 服务端代码 /** 延时 */ exports.timeoutTestData async function (ctx) {console.log(get query:, ctx.request.query);const query ctx.request.query;let timeout query.timeout || 2000;await new Promise(res…

vue专项练习

一、循环实现一个列表的展示及删除功能 1.1 列表展示 1、背景&#xff1a; 完成一个这样的列表展示。使用v-for 循环功能 id接口名称测试人员项目名项目ID描述信息创建时间用例数1首页喵酱发财项目a1case的描述信息2019/11/6 14:50:30102个人中心张三发财项目a1case的描述信…

Redis学习(13)之Lua脚本【环境准备】

文章目录一 Lua入门环境准备1.1 Lua简介1.2 Linux 系统安装Lua1.2.1 Lua 下载1.2.2 Lua 安装1.3 Hello World1.3.1 命令行模式1.3.2 脚本文件模式1.3.3 两种脚本运行方式1.4 Win安装Lua1.4.1 LuaForWindows的安装1.4.2 SciTE修改字体大小1.4.3 SciTE中文乱码1.4.4 SciTE快捷键工…

aws ecs 使用copilot快速创建ecs集群环境并部署服务

参考资料 https://github.com/aws/copilot-cli https://aws.github.io/copilot-cli/ https://github.com/aws-samples/amazon-ecs-cli-sample-app https://ecsworkshop.com/microservices/frontend/#deploy-frontend-0 ecs的服务部署从头开始需要进行以下操作 创建vpc等网…

JS中的事件、DOM操作

一、事件1.1 事件介绍事件: 就是发生在浏览器(页面)上一件事,键盘事件,鼠标事件,表单事件,加载事件等等1.2 事件绑定方式事件要想发生,就得将事件和标签先绑定一个完整的事件有三部分事件源(标签)什么事(事件)响应(动作效果)事件绑定,其实就是事件和标签绑定方式1: 事件源,事件…

IBM Semeru Windows 下的安装 JDK 17

要搞清楚下载那个版本&#xff0c;请参考文章&#xff1a;来聊聊 OpenJDK 和 JVM 虚拟机下载地址semeru 有认证版和非认证版&#xff0c;主要是因为和 OpenJ9 的关系和操作系统的关系而使用不同的许可证罢了&#xff0c;本质代码是一样的。在 Windows 下没有认证版&#xff0c;…

[计算机组成原理(唐朔飞 第2版)]第三章 系统总线(学习复习笔记)

3.1 总线的基本概念 计算机系统的五大部件之间的互连方式有两种 各部件之间使用单独的连线&#xff0c;称为分散连接将各部件连到一组公共信息传输线上&#xff0c;称为总线连接 总线是连接多个部件的信息传输线&#xff0c;是各部件共享的传输介质。 当多个部件与总线相连时&…

【java基础】LinkedList源码解析

文章目录基本介绍构造器基础方法linkFirstlinkLastlinkBeforeunlinkFirstunlinkLastunlinknodeindexOf方法分析总结基本介绍 在java中&#xff0c;LinkedList就是使用双向链表存储元素&#xff0c;既然是链表&#xff0c;那么也就知道了该数据结构擅长添加和删除。对于需要频繁…

线程等待/休眠/状态及 Runnable 和 Callable 的简单使用及原理

关于线程和进程的基本概念☛操作系统中线程和进程的概念理解 这篇文章已经有了很详细的解释, 接下来主要来讲讲线程等待与线程休眠 / 线程的几种状态 / Runnable 和 Callable 与 Thread 的概念和区别及 Executor 框架是什么样的. 关于线程1 线程等待与线程休眠2 线程一共有哪些…

[洛谷-P3698][CQOI2017]小Q的棋盘

一、问题 题目描述 小 Q 正在设计一种棋类游戏。 在小 Q 设计的游戏中&#xff0c;棋子可以放在棋盘上的格点中。某些格点之间有连线&#xff0c;棋子只能在有连线的格点之间移动。整个棋盘上共有 VVV 个格点&#xff0c;编号为 0,1,2,⋯,V−10,1,2,\cdots, V- 10,1,2,⋯,V−…

【C++知识点】C++11 常用新特性总结

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 &#x1f4da;专栏地址&#xff1a;C/C知识点 &#x1f4e3;专栏定位&#xff1a;整理一下 C 相关的知识点&#xff0c;供大家学习参考~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;…

EasyRcovery16免费的电脑照片数据恢复软件

电脑作为一种重要的数据储存设备&#xff0c;其中保存着大量的文档&#xff0c;邮件&#xff0c;视频&#xff0c;音频和照片。那么&#xff0c;如果电脑照片被删除了怎么办&#xff1f;今天小编给大家介绍&#xff0c;误删除的照片从哪里可以找回来&#xff0c;误删除的照片如…

win10打印机拒绝访问解决方法

一直以来,在安装使用共享打印机打印一些文件的时候&#xff0c;会遇到错误提示&#xff1a;“无法访问.你可能没有权限使用网络资源。请与这台服务器的管理员联系”的问题&#xff0c;那为什么共享打印机拒绝访问呢&#xff1f;别着急&#xff0c;下面为大家带来相关的解决方法…

mysql时区问题

设置mysql容器时间与服务器时间一致 问题背景&#xff1a; 今天测试发现一个问题&#xff0c;时间不一致&#xff0c;当工单入库时&#xff0c;其创建时间和更新时间应该是一样的&#xff0c;即使不一样最多只会错几秒的时间&#xff1b;实际上两个时间相差的大概8小时&#…

青少年学AI,Amazon DeepRacer有何魔力?

导读&#xff1a;北京名校中学生可以根据兴趣开发AI模型甚至发表论文&#xff0c;偏远地区的校长还在犹豫“人工智能教育&#xff0c;中考会考吗&#xff1f;高考会加分吗&#xff1f;”教育鸿沟由来已久&#xff0c;绝非仅靠某些企业或教育机构可以扭转&#xff0c;但我们至少…

maven仓库的配置

下载 官网下载&#xff1a;https://maven.apache.org/download.cgi 2. 配置maven环境 右键电脑 ->属性 -> 高级系统设置 -> 环境变量 -> 系统变量-新建 变量名&#xff1a;MAVEN_HOME 变量值为maven的文件安装地址 编辑Path系统变量 新建&#xff1a;%MAVE…