2026-06-18 20:01:30 +08:00
# 继承
概念:
继承是面向对象三大特性之一
可以让一个类在已有类的基础上继续扩展
被继承的类一般叫==父类 / 基类(base class) ==
继承别人的类一般叫==子类 / 派生类(derived class) ==
通常用法:
1. 提取多个类的共同内容,减少重复代码
2. 表达“==is-a==”关系
3. 让子类在父类基础上增加自己的成员和功能
语法:
2026-06-21 09:51:55 +08:00
```csharp
2026-06-18 20:01:30 +08:00
class 子类名 : 父类名
{
2026-06-21 09:51:55 +08:00
2026-06-18 20:01:30 +08:00
}
```
案例:
2026-06-21 09:51:55 +08:00
```csharp
2026-06-18 20:01:30 +08:00
class Animal
{
public string name ;
protected int age ;
2026-06-21 09:51:55 +08:00
2026-06-18 20:01:30 +08:00
public Animal ( string name )
{
this . name = name ;
}
2026-06-21 09:51:55 +08:00
2026-06-18 20:01:30 +08:00
public void Speak ()
{
2026-06-21 09:51:55 +08:00
Console . WriteLine ( "动物发出声音" );
2026-06-18 20:01:30 +08:00
}
}
class Dog : Animal
{
public Dog ( string name , int age ) : base ( name )
{
this . age = age ;
}
2026-06-21 09:51:55 +08:00
2026-06-18 20:01:30 +08:00
public void Bark ()
{
2026-06-21 09:51:55 +08:00
Console . WriteLine ( name );
Console . WriteLine ( age );
Console . WriteLine ( "汪汪" );
2026-06-18 20:01:30 +08:00
}
}
Dog d = new Dog ( "旺财" , 3 );
d . Speak ();
d . Bark ();
```
↑ `Dog : Animal` 就表示 `Dog` 继承了 `Animal`
注意:
1. ==C# 的类只能直接继承一个父类==,也就是单继承
2026-06-21 09:51:55 +08:00
2. 继承可以传递,A 继承 B,B 继承 C,那么 A 也会拥有 C 中可继承的成员
2026-06-18 20:01:30 +08:00
3. ==构造函数不会被继承==,子类只是可以调用父类构造函数
4. 父类的 `private` 成员子类==不能直接访问==,想给子类用一般写 `protected`
5. 结构体 `struct` ==不支持继承类==,但可以实现接口
2026-06-21 09:51:55 +08:00
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. 初学阶段先牢牢记住:==创建子类对象时,一定先把父类部分构造好==
2026-06-18 20:01:30 +08:00
----
# base关键字
概念:
`base` 用来在==子类内部==访问父类成员
最常见的用途就是调用父类构造函数
通常用法:
1. 在子类构造函数中调用父类构造函数
2. 在子类方法中访问父类同名成员或父类方法
语法:
2026-06-21 09:51:55 +08:00
```csharp
2026-06-18 20:01:30 +08:00
class Dog : Animal
{
public Dog ( string name ) : base ( name )
{
2026-06-21 09:51:55 +08:00
2026-06-18 20:01:30 +08:00
}
}
```
2026-06-21 09:51:55 +08:00
2026-06-18 20:01:30 +08:00
调用父类成员:
2026-06-21 09:51:55 +08:00
```csharp
2026-06-18 20:01:30 +08:00
base . 父类成员名
```
案例:
2026-06-21 09:51:55 +08:00
```csharp
2026-06-18 20:01:30 +08:00
class Father
{
public string name ;
2026-06-21 09:51:55 +08:00
2026-06-18 20:01:30 +08:00
public Father ( string name )
{
this . name = name ;
}
2026-06-21 09:51:55 +08:00
2026-06-18 20:01:30 +08:00
public void Say ()
{
2026-06-21 09:51:55 +08:00
Console . WriteLine ( "我是父类" );
2026-06-18 20:01:30 +08:00
}
}
class Son : Father
{
public Son ( string name ) : base ( name )
{
}
2026-06-21 09:51:55 +08:00
2026-06-18 20:01:30 +08:00
public void Test ()
{
base . Say ();
2026-06-21 09:51:55 +08:00
Console . WriteLine ( base . name );
2026-06-18 20:01:30 +08:00
}
}
Son s = new Son ( "小李" );
s . Test ();
```
↑ `base(name)` 是先调用父类构造函数,`base.Say()` 是调用父类方法
注意:
1. `base` 只能在==实例构造函数、实例方法、实例属性访问器==里用
2. ==静态方法里不能用 `base` ==
3. 如果父类没有无参构造函数,子类通常就要显式写 `: base(...)`
2026-06-21 09:51:55 +08:00
4. `base` 是访问父类成员,不是创建一个新的父类对象
2026-06-18 20:01:30 +08:00
----
引用:
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 )
2026-06-21 09:51:55 +08:00
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 )
2026-06-18 20:01:30 +08:00
#继承
#核心