c# 封装、继承和多态
这篇偏理论的,少有代码展示。重点就是,只要知道封装是访问修饰符的应用,继承是代码的重用,多态是可以用同一父类的不同子类的实例给父类型变量赋值,这就行了。本来这3点也没啥难理解的
面向对象编程的3个基本特征
c#是面向对象的语言,所有面向对象的语言(包括Java和c++等)都具有三个基本的特征:
- 封装:把客观事物封装成类,并将类内部的实现隐藏,以保证数据的完整性
- 继承:通过继承可以复用父类的代码
- 多态:允许将子对象赋值给父对象的一种能力
c#中的面向对象编程指的是运用这三个基本特征来编写程序。
封装
封装与字段、属性、访问修饰符,强相关。
封装指的是把类内部的数据隐藏起来,不让对象实例直接对其操作。c#提供了属性机制来对类内部的状态进行操作。在c#中封装可以通过访问修饰符(public/protected/privite/integral)来体现
面向对象编程中的封装特性,是一种保护状态数据完整性的方法,在面向对象编程中应更多地定义私有字段。c#提供属性机制来对这种私有字段数据进行间接地操作,并且可以在属性的定义中加入更多的逻辑判断。利用封装技术,我们可以有效的对外部隐藏类内部的数据,从而避免数据损坏。封装可以避免把一些无意义、不合理的数据赋值给字段。
c#中可用的访问修饰符:
修饰符 | 含义 |
---|---|
无或internal | 只能在当前项目中(同一程序集内)访问类 |
Public | 无限制 |
Private | 只在本类的内部可访问,通过对象或类名也不可 |
Protected | 对所有继承该类的类可访问,类中的方法默认此修饰符 |
Protected internal | 对所有继承该类或在该程序集内的类可访问 |
Abstract | 应用于类表示不能实例化,只能被继承。 |
Sealed | 应用于类表示只能被实例化,不能继承。应用于方法表示不能被子类重写。 |
以上可以两两组合使用空格隔开就行。除了后两个之外,其他的都可用于修饰类中的成员。
继承
注意:关于词义上,继承、派生 是等同的;父类、基类 是等同的;
目的和作用:
对现有的类型进行扩展,以便添加更多的功能,也是实现了代码的重用;
一些规则:
- 子类通过继承可以获得父类除构造函数和析构函数之外的所有成员。在子类中,我们可以访问它的父类的public或protected成员,不可以访问其internal和private成员。
- c#的类仅支持派生自一个基类,但可以继承多个接口。
- 父类与子类是“is——a”关系,即 有一种父类是子类,比如有一种动物是熊猫; 这会导致: Animal a=new Bird();是合法的;其中 Bird 类继承自animal类。
- c#支持重写方法和属性,但不支持重写字段和任何静态成员;
- 派生类不能删除它所继承的任何成员;
- 调用基类的隐藏成员(如被覆盖的方法),可用base点成员名一个子类的实例必须伴随着其每一个父类的实例。
子类的初始化顺序
使用了继承之后,当我们创建一个子类的对象时,除了会调用子类的构造函数外,同时也会调用(优先调用)基类的无参构造函数。子类的初始化顺序如下:
- 初始化类的实例字段。
- 调用基类的无参构造函数,如果没有指明基类,则调用System.Object的构造函数;
- 调用子类的构造函数。
集合初始化器:用来完成对集合中的元素的初始化。怎么用呢?比如:
定义一个集合变量:
List<string> names= new List<string>();
重复用Add方法添加多个元素:
names.Add( “巨婴一号” ); ……
但若是用集合初始化器,就可以这样弄:
List<string> names= new List<string>{ “巨婴一号”,“巨婴二号”,“巨婴三号” }; 这样就明显减少代码量了,呵呵。但这一特性同样依赖编译器提供的帮助,它首先会调用List的无参构造函数,然后调用add方法,逐个的将初始化的内容添加了进去。这一点可以用reflector工具查看,或看IL代码。
base关键字
base关键字用于从派生类中访问基类成员,有以下用法:
- 它在派生类的方法中调用基类中被派生类重写的方法
- 派生类的构造函数的参数列表后的 构造函数初始化语句:
若为:base.(与基类某构造函数相关的参数列表),则调用基类中的的那个构造函数;
注意:在派生类某构造函数中的参数列表为空,同等于其参数列表后有 :base(),即会隐式调用基类无参的构造函数;
若为:this。(与派生类构造函数相对应的参数列表),则调用该类的某个函数
这种语法挺好用,简化代码,减少不必要的重复代码。像一个类有好几个构造函数,但多个函数有执行一些公共的代码的情况,那么可以把这些公共代码放到一个构造函数中,被其他需要的通过 构造函数初始化语句即:this.(参数列表) 来调用; 另外,若这个构造函数不能完全初始化一个对象,即只会初始化一部分,那么可以把该函数设为private,而不是public;
方法重写
只有基类成员声明为virtual或abstract时,该成员才能被派生类重写;而如果子类想改变虚方法的实现行为,则必须使用override关键字。
派生类重写基类时,可用new或override,但影响不同;??
//如果想在派生类中定义与基类成员同名的成员。则可以使用new关键字把基类成员隐藏起来。但要是仍然想访问基类中的成员,则可使用强制类型转换,把子类强制转换为基类类型,从而访问隐藏的基类成员。
//如果子二代不想让子三代重写,自己继承到的,已经自己重写过的虚方法:可在类中对方法用“sealed override”修饰。
多态
由来:子类可以继承基类的成员,那么可能不同子类就都有了相同的行为,但是有时某些子类的有些行为需要相互区别,则子类就需要覆写父类中的方法来实现子类特有的行为,这样的技术在面向对象编程中就是多态。多态即相同类型(同一个接口或父类)的对象调用相同的方法却表现出不同行为的现象。
若要 A a=new B( );
合法,需满足两个条件之一:
- A是父类,B是A的子类。
- A是一个接口,B实现了A。
更新于:2023-4-17
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)