C#学习笔记_继承

基本概念

继承是面向对象程序设计中最重要的概念之一。继承允许我们根据一个类来定义另一个类,这使得创建和维护应用程序变得更容易。同时也有利于重用代码和节省开发时间。

当创建一个类时,程序员不需要完全重新编写新的数据成员和成员函数,只需要设计一个新的类,继承了已有的类的成员即可。这个已有的类被称为的基类,这个新的类被称为派生类。基类有时又叫父类、超类,派生类有时又叫子类。

在逻辑上,可以认为,派生类属于基类,例如,在描述图像时,可以用图形Shape作为基类,正方形Square作为派生类,此时有正方形属于图形的从属关系。

需要注意的是,C#不支持多重继承。意思就是一个派生类只能继承一个基类。当然,基类也可以继承自其它的基类。

继承语法如下:

cs 复制代码
class BaseClass{
    //BaseClass基类成员
}
class DerivedClass : BaseClass{
    //DerivedClass派生类成员
}

一般会在派生类名后添加冒号加基类名,表示派生类继承于基类。

sealed

默认情况下,所有类都可以通过继承得到。但是你可以指定某个类不能作为基类或是指定某个类只能用作基类。例如,指定类A不能作为基类:

cs 复制代码
public sealed class A {
    //A类成员
}

此时,我们使用关键字sealed将类限定为密封类,sealed修饰符将阻止其他类继承此类。可以简单理解为,sealed关键字使其他类不能继承于类A。一般称sealed关键字修饰的类为密封类。

abstract

当使用关键字abstract修饰某一类,则该类只能作为基类,不能被实例化。例如,指定类B不能被实例化,类C继承于类B:

cs 复制代码
public abstract class B{
    //类B的成员
}
public class C : B{
    //类C的成员
}

实际上,abstract修饰符表明所修饰内容尚未完全实现。abstract修饰符也可用于函数、属性、索引和事件等,被abstract限定的类成员或包含在abstract类中的成员必须由继承此类的子类实现

例如下面的实例:

cs 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace K1
{
    public abstract class Shape //基类Shape表示形状
    {
        public abstract int Area(); //获取形状面积,成员函数未完全实现
    }
    public class Square : Shape //派生类Square表示正方形
    {
        int side;

        public Square()
        {
            side = 0;
        }

        public Square(int side)
        {
            this.side = side;
        }
        public override int Area()  //在派生类中成员函数Area实现。
        {
            return side * side;
        }
    }

    public class myCaller
    {
        public static void Main(string[] args)
        {
            string side = Console.ReadLine();
            Square s = new Square(Convert.ToInt32(side));
            Console.WriteLine("Square Area:" + s.Area());
            Console.ReadKey();
        }
    }
}

需要注意,子类的访问级别不能高于基类,上面的基类Shape与派生类Square均为public访问级别,符合规则。上面实例输入输出如下所示:

>>>10

Square Area:100

代码中,定义的基类Shape以及其中成员函数Area使用abstract修饰,故Shape类必须作为基类,且成员函数Area必须在派生类Square中实现。

abstract类可称为抽象类,抽象类有如下性质:

  • 抽象类不能被实例化;
  • 抽象类可能包含抽象方法和抽象存取器;
  • 抽象类不能被sealed修饰,sealedabstract作用意义互相冲突。使用sealed修饰的类不能被继承,使用abstract修饰的类只能被继承;
  • 继承自抽象类的子类必须实现抽象类中声明的抽象函数和抽象存取器。

在函数或属性声明处使用abstract修饰符,用来表明该函数或属性不可实现。abst\fract修饰的函数有如下几个特点:

  • 抽象方法声明只允许在抽象类中使用;
  • 由于抽象方法没有提供具体的实现过程,所以不需包含函数体;方法声明以;结尾,不需使用{};具体的实现过程将会在子类中,使用override标志;
  • 在抽象方法声明中不允许使用staticvirtual
  • 抽象方法是一种隐式的虚函数virtual method

抽象属性表现类似于抽象方法,除了声明和调用语法的不同之外:

  • 在静态(static修饰)属性中不可使用abstract修饰符;
  • 在基类中声明的抽象属性可继承到子类中。并使用override重写。

override

上面的实例,在派生类Square中的成员函数Area中,涉及到另外一个关键字overrideoverride修饰符用来拓展或修改继承自基类中的方法、属性、索引或事件,其中基类中的方法、属性、索引或事件使用abstractvirtual修饰。

其中,override重写实现的方法声明必须与基类中方法拥有相同的函数签名。

override不能重写非虚方法或静态方法,抽象方法是一种隐式的虚方法,在基类中的方法必须使用virtualabstractoverride修饰。

使用override修饰方法声明不能更改继承基类虚方法的访问修饰符,两者需保持一致。

在使用override修饰的方法时不能够使用修饰符newstaticvirtual。使用override修饰的属性类似。

多态

多态可理解为多种形态,在派生于同一个类的不同子类对象上执行任务操作时,多态性十分的高效,使用的代码最少。只要在继承层次中有一个相同多的类,那么就可使用多态性进行处理。

下面的代码实例可体现多态使用:

cs 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace K2
{
    public abstract class Shape //基类Shape
    {
        public abstract int Area(); //获取形状面积
    }

    //派生类圆形Circular类和正方形Square类
    public class Circular : Shape
    {
        int radius; //成员radius表示圆形半径

        public Circular(int radius)
        {
            this.radius = radius;
        }
        public override int Area()  //重写基类成员函数
        {
            return radius * radius * 3;
        }

        public void radiusSet(int radius)
        {
            this.radius = radius;
        }
    }

    public class Square : Shape
    {
        int side;   //成员side表示正方形边长
        public Square(int side)
        {
            this.side = side;
        }

        public override int Area()
        {
            return side * side;
        }
    }

    public class myCaller
    {
        public static void Main(string[] args)
        {
            Circular c = new Circular(4);
            Square s = new Square(4);

            Shape shape1 = s;   //子类对象可被当做基类对象使用
            Shape shape2 = c;

            Console.WriteLine("Square Area:" + shape1.Area());  //多个子类便可提供多种Area实现
            Console.WriteLine("Circular Area:" + shape2.Area());

        }
    }
}

多态有多种应用场景:

一、子类对象可被当做基类对象使用

在运行时,子类对象可被当做基类对象使用,例如当对象用于方法参数、集合或数组的时候,该对象的声明类型不再与运行时类型相同。例如上面的实例中,Shape类对象接受Circular类对象、Square类对象无需强制类型转换。此时对象shape2不能使用Circular类中的成员函数RadiusSet,如果想要调用,可以使用强制类型转换将Shape类对象转换回Circular类对象。

cs 复制代码
Circular c2=(Circular)shape2;
c2.RadiusSet(10);

二、子类可提供多种基类方法实现

使用继承的时候,子类可使用override重写基类中定义和实现的虚方法,多个子类便可提供多种实现。在运行时,当客户端代码调用该方法的时,CLR查询对象的运行时类型,会调用重写的虚方法。所以,源码中可通过调用基类中的方法,具体执行的则是子类中已重写的方法。

例如上面的实例,子类便使用override重写了基类中定义的Area方法,此后Shape类对象分别接受s、c,调用Area方法时,Shape1使用的是Square类中实现的方法,Shape2使用的是Circular类实现的方法。

相关推荐
冰帝海岸1 小时前
01-spring security认证笔记
java·笔记·spring
小二·2 小时前
java基础面试题笔记(基础篇)
java·笔记·python
向宇it3 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
九鼎科技-Leo3 小时前
什么是 WPF 中的依赖属性?有什么作用?
windows·c#·.net·wpf
朝九晚五ฺ4 小时前
【Linux探索学习】第十四弹——进程优先级:深入理解操作系统中的进程优先级
linux·运维·学习
Heaphaestus,RC4 小时前
【Unity3D】获取 GameObject 的完整层级结构
unity·c#
baivfhpwxf20234 小时前
C# 5000 转16进制 字节(激光器串口通讯生成指定格式命令)
开发语言·c#
直裾4 小时前
Scala全文单词统计
开发语言·c#·scala
wusong9995 小时前
mongoDB回顾笔记(一)
数据库·笔记·mongodb
猫爪笔记5 小时前
前端:HTML (学习笔记)【1】
前端·笔记·学习·html