:::danger 继承与派生其实是同一过程从不同的角度看,我们将保持已有类的特性而构造新类的过程称为继承,说白了继承的目的就是实现原来设计与代码的重用,希望尽量利用原有的类。
然而当新的问题出现,原有程序无法解决或不能完全解决时,需要对原有程序进行改造,在已有类的基础上新增自己的特性而产生新类的过程称为派生。 :::

类的继承

  1. using System;
  2. // OOP:Object Oriented Programming,面向对象程序设计
  3. namespace HelloOOP
  4. {
  5. class Program
  6. {
  7. static void Main(string[] args)
  8. {
  9. // 证明car class是由vehicle class派生出来的
  10. //Type type = typeof(Car);
  11. //Type type1 = type.BaseType;
  12. //Console.WriteLine(type1.FullName);
  13. // 未指明基类的类的基类为object class
  14. Type type = typeof(Car);
  15. Type type1 = type.BaseType;
  16. Type tTOP = type1.BaseType;
  17. Console.WriteLine(tTOP.FullName);
  18. // 此句证明对于vehicle class ,其父类object class的父类为空
  19. Console.WriteLine(tTOP.BaseType == null);
  20. }
  21. }
  22. // Vehicle:交通工具
  23. class Vehicle object
  24. {
  25. }
  26. // 使用 子类 :父类,就形成了继承链
  27. // car继承了vehicle
  28. class Car : Vehicle
  29. {
  30. }
  31. }

is a 概念

is a:一个派生类(子类)的实例,从语义上来说也是一个基类(父类)的实例。

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. Car car = new Car();
  6. Vehicle vehicle = new Vehicle();
  7. Console.WriteLine(car is Vehicle);
  8. Console.WriteLine(car is object);
  9. Console.WriteLine(vehicle is Car);
  10. // 子类在父类的范围之内,但父类的范围不一定包含子类。即子类是父类的充分不必要条件
  11. //程序为消除“二义性”,输出结果为FALSE;
  12. }
  13. }
  14. class Vehicle
  15. {
  16. }
  17. class Car : Vehicle
  18. {
  19. }

其输出结果为

True; True; False;

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. Vehicle vehicle1 = new Car();
  6. Object obj1 = new Vehicle();
  7. Object obj2 = new Car();
  8. }
  9. }
  10. class Vehicle
  11. {
  12. }
  13. class Car : Vehicle
  14. {
  15. }

里氏转换

1)子类可以赋值给父类

2)如果父类中装的是子类对象,那么可以讲这个父类强转为子类对象

知识点

  • 使用sealed修饰某一类,此类将会变成“封闭类”,此类将不能变为基类来使用,即无法被继承

image.png

  • C#中一个类当中一个类最多只能有一个基类,只支持单继承

    C++ 支持多继承,但它也受菱形继承的困扰

    菱形继承

    菱形继承即多个类继承了同一个公共基类,而这些派生类又同时被一个类继承。

image.png

  • 子类的访问权限不能超越父类

子类的访问权限可与父类持平
父类的访问权限可超越子类
image.png子类不可超越父类
image.png子类与父类持平
image.png父类可超越子类访问权限

继承的本质

Timothy个人定义:继承的本质是派生类在基类已有的成员基础上,对基类进行的横向和纵向的扩展。

  • 派生类在基类已有的成员基础:当继承发生时,子类对父类的继承是全盘继承

    儿子把父亲的所有家产一个不落全拿过来

:::info 只能扩展不能缩减,这是静态类型语言(C#、C++、Java 等)的特征,继承时类成员只能越来越多。
动态类型语言(Python、JavaScript)可以移除类成员。 ::: :::danger 在进行类库设计的时,对于新引用的类时,一定要小心,防止出现继承链及API污染 :::

  • 横向扩展:对类成员个数的扩充
  • 纵向扩展:对类成员(重写override)版本的更新 :::warning 对于一定存在扩展,是因为若不存在扩展,子类与父类不存在区别,及失去了子类存在的意义。 :::

    特点:子类对父类的继承是全盘继承以及成员只能扩展不能缩减

    1. class Program
    2. {
    3. static void Main(string[] args)
    4. {
    5. RaceaCar raceaCar = new RaceaCar();
    6. raceaCar.
    7. }
    8. }
    9. class Vehicle
    10. {
    11. public string Owner { get; set; }
    12. }
    13. class Car:Vehicle
    14. {
    15. }
    16. class RaceaCar:Car
    17. {
    18. }

    :::danger C#内无操作符对父类中的成员进行移除的操作符,不支持将父类中的成员进行移除 ::: image.png
    raceCar中存在其余成员,其来自于object类中·的成员。

    特点: 基类对象的定义以及如何通过基类对象对基类的类成员进访问

    1. class Program
    2. {
    3. static void Main(string[] args)
    4. {
    5. Car car = new Car();
    6. // Car car = new Car("timothy");
    7. Console.WriteLine(car.Owner);
    8. }
    9. }
    10. class Vehicle
    11. {
    12. public Vehicle()
    13. {
    14. this.Owner = "N/A";
    15. }
    16. /*public Vehicle(string Owner)
    17. *{
    18. * this.Owner = Owner;
    19. *}
    20. *示例A
    21. */
    22. public string Owner{ get; set; }
    23. }
    24. class Car : Vehicle
    25. {
    26. public Car()
    27. {
    28. this.Owner = "Car Owner";
    29. }
    30. // 当使用“示例A”是,Car会产生报错解决方法如下
    31. /* 1.
    32. * public Car():base("N/A")
    33. * {
    34. * this.Owner = "Car Owner";
    35. * }
    36. *
    37. * 2.
    38. * public Car(string Owner):base(Owner)
    39. * {
    40. * this.Owner = Owner;
    41. * // 由于在基类构造器中已存在Owner的值传给Owner参数值
    42. * // 因此上述一条语句可省略
    43. * }
    44. */
    45. public void ShowOwner()
    46. {
    47. // 打印出子类对象的Owner的值
    48. Console.WriteLine(this.Owner);
    49. // 打印出基类对象的Owner的值
    50. Console.WriteLine(base.Owner);// base只能向上访问一层,且不能重复叠加
    51. /*错误示范
    52. *Console.WriteLine(base.base.Owner);
    53. */
    54. }
    55. }

    上述代码注释内运行代码展示说明:基类中的构造器不可被子类继承

    类成员的访问级别

    类成员的访问级别以类的访问级别为上限。

实例私有字段
命名偏好
随着越来越多 C++、Java 程序员加入 .NET 社区,private 字段的命名普遍遵循 下划线 + 小写
例:private int _rpm;

在团队合作中,自己写的类或方法不想被他人调用时,推荐的做法就是不用 public 进行修饰。
如果应该封装的成员没有封装,对方只要发现能够调用,又能解决问题,他就一定会去用,进而导致一些不确定的问题。

关键字 访问级别
public 25类的继承,类成员访问 - 图7
protected internal 25类的继承,类成员访问 - 图8
internal 25类的继承,类成员访问 - 图9
protected 25类的继承,类成员访问 - 图10
private 25类的继承,类成员访问 - 图11

C# 7.2 推出了最新的 Private Protected: The member declared with this accessibility can be visible within the types derived from this containing type within the containing assembly. It is not visible to any types not derived from the containing type, or outside of the containing assembly. i.e., the access is limited to derived types within the containing assembly.( Private Protected 仅对程序集内的派生类可见)

面向对象的实现风格

开放心态,不要有语言之争。

我们现在学到的封装、继承、多态的风格是基于类的(Class-based)
还有另外一个非常重要的风格就是基于原型的(Prototype-based),JavaScript 就是基于原型的面向对象。

Java 也是基于类的,让我们一撇 Java:

  1. package com.ccc;
  2. public class Main {
  3. public static void main(String[] args) {
  4. Car car = new Car();
  5. car.owner = "Timothy";
  6. System.out.println(car.owner);
  7. }
  8. }
  9. class Vehicle{
  10. public String owner;
  11. }
  12. class Car extends Vehicle{
  13. }