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点成员名一个子类的实例必须伴随着其每一个父类的实例。

子类的初始化顺序

使用了继承之后,当我们创建一个子类的对象时,除了会调用子类的构造函数外,同时也会调用(优先调用)基类的无参构造函数。子类的初始化顺序如下:

  1. 初始化类的实例字段。
  2. 调用基类的无参构造函数,如果没有指明基类,则调用System.Object的构造函数;
  3. 调用子类的构造函数。

集合初始化器:用来完成对集合中的元素的初始化。怎么用呢?比如:

定义一个集合变量: 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

posted @   AI大胜  阅读(596)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示