# 继承 概念: 继承是面向对象三大特性之一 可以让一个类在已有类的基础上继续扩展 被继承的类一般叫==父类 / 基类(base class)== 继承别人的类一般叫==子类 / 派生类(derived class)== 通常用法: 1. 提取多个类的共同内容,减少重复代码 2. 表达“==is-a==”关系 3. 让子类在父类基础上增加自己的成员和功能 语法: ```csharp class 子类名 : 父类名 { } ``` 案例: ```csharp class Animal { public string name; protected int age; public Animal(string name) { this.name = name; } public void Speak() { Console.WriteLine("动物发出声音"); } } class Dog : Animal { public Dog(string name, int age) : base(name) { this.age = age; } public void Bark() { Console.WriteLine(name); Console.WriteLine(age); Console.WriteLine("汪汪"); } } Dog d = new Dog("旺财", 3); d.Speak(); d.Bark(); ``` ↑ `Dog : Animal` 就表示 `Dog` 继承了 `Animal` 注意: 1. ==C# 的类只能直接继承一个父类==,也就是单继承 2. 继承可以传递,A 继承 B,B 继承 C,那么 A 也会拥有 C 中可继承的成员 3. ==构造函数不会被继承==,子类只是可以调用父类构造函数 4. 父类的 `private` 成员子类==不能直接访问==,想给子类用一般写 `protected` 5. 结构体 `struct` ==不支持继承类==,但可以实现接口 6. 子类对象本质上也是父类对象的一种,所以继承是后面学[[多态vob|多态]]和[[里氏替换原则]]的基础 ---- # 继承中的构造函数 概念: 继承里最容易混淆的一点就是==“子类会继承父类成员,但不会继承父类构造函数”== 当你 `new` 一个子类对象时,不只是创建“子类自己的部分”,还要先把==父类那一部分==初始化好 所以子类构造函数最终一定会调用某个父类构造函数 通常用法: 1. 让父类负责初始化“大家共有”的数据 2. 让子类只负责补充自己的初始化逻辑 3. 保证对象创建出来时就是完整、可用的状态 核心规则: 1. ==父类构造函数不会被继承== 2. ==子类构造函数最终一定会调用某个父类构造函数== 3. 如果子类没有显式写 `: base(...)`,编译器会尝试补一个 `: base()` 4. 如果父类没有无参构造函数,子类就必须显式写 `: base(...)` 5. 构造函数体的执行顺序可以先记成:==先父类,后子类== 案例1:显式调用父类构造函数 ```csharp class Person { public string Name; public Person(string name) { Name = name; Console.WriteLine("Person构造"); } } class Student : Person { public int Score; public Student(string name, int score) : base(name) { Score = score; Console.WriteLine("Student构造"); } } Student s = new Student("小明", 100); ``` 执行理解: 1. 先执行 `Person(string name)` 2. 再执行 `Student(string name, int score)` 的函数体 案例2:父类有无参构造函数时,可以省略 `base()` ```csharp class Animal { public Animal() { Console.WriteLine("Animal构造"); } } class Dog : Animal { public Dog() { Console.WriteLine("Dog构造"); } } Dog d = new Dog(); ``` ↑ 这里虽然没写 `: base()`,但编译器会默认帮你补上 案例3:父类没有无参构造函数时,子类必须显式写 `base(...)` ```csharp class Animal { public string Name; public Animal(string name) { Name = name; } } class Dog : Animal { public Dog(string name) : base(name) { } } ``` 错误示意: ```csharp class Dog : Animal { public Dog() { } } ``` ↑ 这时会报错,因为编译器默认想调用 `base()`,但父类根本没有无参构造函数 案例4:子类构造函数之间也可以先用 `this(...)` 串起来 ```csharp class Animal { public string Name; public Animal(string name) { Name = name; } } class Dog : Animal { public int Age; public Dog() : this("默认小狗", 0) { } public Dog(string name, int age) : base(name) { Age = age; } } ``` 理解: `Dog()` 没有直接 `base(name)`,而是先调用同类里的 `Dog(string name, int age)` 然后再由那个构造函数去调用 `base(name)` 所以最终调用链还是会到父类构造函数 注意: 1. 一个构造函数初始化器里==只能写一个==,也就是写了 `this(...)` 就不能再写 `base(...)` 2. 但 `this(...)` 调到的另一个构造函数里,仍然可以写 `base(...)` 3. 不要在子类里重复初始化父类已经负责的数据,父类自己的数据最好交给父类构造函数处理 4. 初学阶段先牢牢记住:==创建子类对象时,一定先把父类部分构造好== ---- # base关键字 概念: `base` 用来在==子类内部==访问父类成员 最常见的用途就是调用父类构造函数 通常用法: 1. 在子类构造函数中调用父类构造函数 2. 在子类方法中访问父类同名成员或父类方法 语法: ```csharp class Dog : Animal { public Dog(string name) : base(name) { } } ``` 调用父类成员: ```csharp base.父类成员名 ``` 案例: ```csharp class Father { public string name; public Father(string name) { this.name = name; } public void Say() { Console.WriteLine("我是父类"); } } class Son : Father { public Son(string name) : base(name) { } public void Test() { base.Say(); Console.WriteLine(base.name); } } Son s = new Son("小李"); s.Test(); ``` ↑ `base(name)` 是先调用父类构造函数,`base.Say()` 是调用父类方法 注意: 1. `base` 只能在==实例构造函数、实例方法、实例属性访问器==里用 2. ==静态方法里不能用 `base`== 3. 如果父类没有无参构造函数,子类通常就要显式写 `: base(...)` 4. `base` 是访问父类成员,不是创建一个新的父类对象 ---- 引用: 1. Microsoft Learn: [Inheritance - derive types to create more specialized behavior](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/object-oriented/inheritance) 2. Microsoft Learn: [Inheritance in C# and .NET](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/tutorials/inheritance) 3. Microsoft Learn: [Constructors (C# Programming Guide)](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors) 4. Microsoft Learn: [Using constructors](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/using-constructors) 5. Microsoft Learn: [base (C# Reference)](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/base) 6. Microsoft Learn: [protected (C# Reference)](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/protected) #继承 #核心