继承
什么是继承
继承是面向对象编程的核心机制,允许一个类复用另一个类的成员并扩展新功能。C#仅支持单继承,即一个类只能有一个直接基类。
继承语法
使用 class 派生类 : 基类 声明继承关系。派生类自动获得基类的所有非私有成员。
示例
CSHARP
class Animal
{
public string Name { get; set; }
public void Eat()
{
Console.WriteLine($"{Name} is eating.");
}
}
class Dog : Animal
{
public void Bark()
{
Console.WriteLine($"{Name}: Woof!");
}
}
class Program
{
static void Main()
{
Dog dog = new Dog { Name = "Buddy" };
dog.Eat();
dog.Bark();
}
}
TEXT
Buddy is eating.
Buddy: Woof!
base 关键字
base 用于调用基类的构造函数和成员方法。在构造函数中通过 base(args) 传递参数给父类构造器,在方法中通过 base.Method() 调用父类实现。
示例
CSHARP
class Person
{
public string Name { get; }
public Person(string name)
{
Name = name;
}
public virtual void Introduce()
{
Console.WriteLine($"I am {Name}.");
}
}
class Student : Person
{
public int Grade { get; }
public Student(string name, int grade) : base(name)
{
Grade = grade;
}
public override void Introduce()
{
base.Introduce();
Console.WriteLine($"I am in grade {Grade}.");
}
}
class Program
{
static void Main()
{
Student s = new Student("Alice", 3);
s.Introduce();
}
}
TEXT
I am Alice.
I am in grade 3.
方法重写 virtual/override
基类用 virtual 标记可重写的方法,派生类用 override 提供新实现。这是实现多态的基础。
示例
CSHARP
class Shape
{
public virtual double Area()
{
return 0;
}
}
class Circle : Shape
{
public double Radius { get; set; }
public Circle(double radius)
{
Radius = radius;
}
public override double Area()
{
return Math.PI * Radius * Radius;
}
}
class Rectangle : Shape
{
public double Width { get; set; }
public double Height { get; set; }
public Rectangle(double w, double h)
{
Width = w;
Height = h;
}
public override double Area()
{
return Width * Height;
}
}
class Program
{
static void Main()
{
Shape[] shapes = { new Circle(2), new Rectangle(3, 4) };
foreach (Shape s in shapes)
{
Console.WriteLine($"Area: {s.Area():F2}");
}
}
}
TEXT
Area: 12.57
Area: 12.00
方法隐藏 new
如果派生类定义了与基类同名的方法但未使用 override,编译器会发出警告。使用 new 关键字可以显式隐藏基类方法,表明这是独立的方法而非重写。
示例
CSHARP
class Base
{
public void Greet()
{
Console.WriteLine("Hello from Base");
}
}
class Derived : Base
{
public new void Greet()
{
Console.WriteLine("Hello from Derived");
}
}
class Program
{
static void Main()
{
Derived d = new Derived();
d.Greet();
Base b = d;
b.Greet();
}
}
TEXT
Hello from Derived
Hello from Base
💡
new 隐藏与 override 重写的区别:通过基类引用调用时,new 执行基类版本,override 执行派生类版本。
sealed 禁止继承
sealed 修饰类表示该类不能被继承,修饰方法表示该方法不能被进一步重写。
示例
CSHARP
class Config
{
public virtual void Load()
{
Console.WriteLine("Loading config...");
}
}
class JsonConfig : Config
{
public sealed override void Load()
{
Console.WriteLine("Loading JSON config...");
}
}
sealed class FinalClass
{
public void DoWork() { }
}
class Program
{
static void Main()
{
JsonConfig cfg = new JsonConfig();
cfg.Load();
}
}
TEXT
Loading JSON config...
⚠️
JsonConfig.Load 被 sealed 修饰后,从 JsonConfig 派生的类无法再重写 Load。FinalClass 被 sealed 修饰后,任何类都无法继承它。
继承的构造函数链
创建派生类对象时,基类构造函数总是先于派生类构造函数执行。如果基类没有无参构造函数,派生类必须显式调用 base(args)。
示例
CSHARP
class Vehicle
{
public string Type { get; }
public Vehicle(string type)
{
Type = type;
Console.WriteLine($"Vehicle({type}) constructed");
}
}
class Car : Vehicle
{
public string Brand { get; }
public Car(string brand) : base("Car")
{
Brand = brand;
Console.WriteLine($"Car({brand}) constructed");
}
}
class Program
{
static void Main()
{
Car car = new Car("Toyota");
}
}
TEXT
Vehicle(Car) constructed
Car(Toyota) constructed
object 根类
C#中所有类型都继承自 System.Object(别名 object)。它提供了 ToString()、Equals()、GetHashCode()、GetType() 等基础方法。
示例
CSHARP
class Point
{
public int X { get; }
public int Y { get; }
public Point(int x, int y)
{
X = x;
Y = y;
}
public override string ToString()
{
return $"({X}, {Y})";
}
public override bool Equals(object obj)
{
if (obj is Point other)
{
return X == other.X && Y == other.Y;
}
return false;
}
public override int GetHashCode()
{
return HashCode.Combine(X, Y);
}
}
class Program
{
static void Main()
{
Point p1 = new Point(1, 2);
Point p2 = new Point(1, 2);
Console.WriteLine(p1.ToString());
Console.WriteLine(p1.Equals(p2));
Console.WriteLine(p1.GetType().Name);
}
}
TEXT
(1, 2)
True
Point
is 和 as 运算符
is 用于类型检查,返回 bool;as 用于安全类型转换,转换失败返回 null 而不抛异常。
示例
CSHARP
class Animal { }
class Cat : Animal
{
public void Meow() { Console.WriteLine("Meow!"); }
}
class Dog : Animal
{
public void Bark() { Console.WriteLine("Woof!"); }
}
class Program
{
static void Main()
{
Animal a = new Cat();
if (a is Cat)
{
Console.WriteLine("a is a Cat");
}
if (a is Dog)
{
Console.WriteLine("a is a Dog");
}
else
{
Console.WriteLine("a is not a Dog");
}
Cat c = a as Cat;
if (c != null)
{
c.Meow();
}
Dog d = a as Dog;
Console.WriteLine($"as Dog result is null: {d == null}");
}
}
TEXT
a is a Cat
a is not a Dog
Meow!
as Dog result is null: True
💡 C# 7+ 支持
is 模式匹配:if (a is Cat cat) 可以在检查的同时声明变量。
❓ 常见问题
Q C#支持多重继承吗?
A 不支持。一个类只能有一个直接基类,但可以实现多个接口。
Q 不写override直接写同名方法会怎样?
A 编译器产生警告,该方法默认隐藏基类方法,建议加
new 显式声明。Q base关键字能在静态方法中使用吗?
A 不能。base和this都指向实例,静态方法没有实例上下文。
Q sealed类有什么实际意义?
A 防止类被继承,保证实现不被修改,同时JIT可以进行更多优化。
Q is和as有什么区别?
A is返回bool做类型判断,as尝试转换并返回对象或null,as不能用于值类型。
📖 小节
- 继承用
class 派生类 : 基类语法,C#只支持单继承 base关键字调用父类构造函数和成员方法virtual/override实现方法重写,是多态的基础new关键字显式隐藏基类方法,与重写行为不同sealed修饰类禁止继承,修饰方法禁止进一步重写- 构造函数从基类到派生类依次执行
- 所有类型继承自
object,可重写ToString、Equals、GetHashCode is做类型检查,as做安全转换
📝 作业
- 定义一个
Employee基类(含Name和Salary属性),派生Manager类(额外含Level属性),在Manager构造函数中用base调用父类构造器。 - 在
Employee中定义virtual void Work()方法,在Manager中用override重写,并在重写方法里调用base.Work()。 - 创建一个
Employee[]数组,包含Employee和Manager对象,用is运算符判断类型并输出不同信息。 - 重写
Manager的ToString()方法,返回包含Name、Salary、Level的字符串。 - 声明一个
sealed类PayCalculator,尝试编写一个类继承它,观察编译错误。



