单继承

public class Animal
{
    public string Name = "";
    public void Sleep() => Console.WriteLine($"{Name} sleeping");
}

public class Dog : Animal
{
    public void Bark() => Console.WriteLine($"{Name} woof!");
}

var d = new Dog { Name = "Rex" };
d.Sleep();   // 继承自 Animal
d.Bark();    // 自己的

C# 只有单继承——一个类只能有一个基类。但可以实现多个接口(第 11 篇)。

调用父构造

public class Animal
{
    public string Name;
    public Animal(string name) { Name = name; }
}

public class Dog : Animal
{
    public string Breed;
    public Dog(string name, string breed) : base(name)
    {
        Breed = breed;
    }
}

: base(...) 在自己构造前调父构造。

virtual + override

public class Animal
{
    public virtual void Speak() => Console.WriteLine("...");
}

public class Cat : Animal
{
    public override void Speak() => Console.WriteLine("meow");
}

public class Dog : Animal
{
    public override void Speak() => Console.WriteLine("woof");
}

Animal a = new Cat();
a.Speak();    // meow(运行时多态——根据实际类型调)
  • 父用 virtual 标记"可以被子类重写"
  • 子用 override 重写
  • 多态生效:声明类型是 Animal,调用走实际类型的实现

不用 virtual = 隐藏父方法

public class Animal
{
    public void Speak() => Console.WriteLine("...");
}

public class Cat : Animal
{
    public new void Speak() => Console.WriteLine("meow");
}

Animal a = new Cat();
a.Speak();    // "..."(按声明类型,不多态)

Cat c = new Cat();
c.Speak();    // "meow"

new 关键字明确"故意隐藏父方法"——但 99% 时候你想要的是 override

abstract

public abstract class Shape
{
    public abstract double Area();      // 没有实现
    public virtual void Describe() => Console.WriteLine($"Area = {Area()}");
}

public class Circle : Shape
{
    public double Radius;
    public override double Area() => Math.PI * Radius * Radius;
}

// new Shape() ❌ 不能实例化抽象类
var c = new Circle { Radius = 5 };
c.Describe();

abstract class:不能实例化,强制子类提供实现。 abstract method:只签名没体,子类必须 override。

sealed

public sealed class Config { ... }     // 类:不能被继承

public class Animal
{
    public virtual void Speak() { }
}

public class Cat : Animal
{
    public sealed override void Speak() { ... }   // 方法:子类不能再 override
}

默认 sealed 是好实践——避免误继承造成的脆弱设计。需要被继承的类显式 unseal。

protected

public class Animal
{
    protected int _id;     // 子类能访问,外部不能
}

public class Dog : Animal
{
    public void X() { _id = 5; }   // ✅
}

var a = new Animal();
a._id = 5;   // ❌

类型转换

Animal a = new Dog();

// 向下转换
if (a is Dog d)        // 模式匹配
{
    d.Bark();
}

Dog d2 = (Dog)a;       // 显式 cast,失败抛 InvalidCastException
Dog? d3 = a as Dog;    // as:失败返 null(只对引用类型 / 可空类型)

is / as 更安全——优先用 if (a is Dog d) ...

base 调父方法

public class Cat : Animal
{
    public override void Speak()
    {
        base.Speak();           // 先调父
        Console.WriteLine("meow");
    }
}

object:所有类的根

object o = 42;          // int 也是 object(装箱)
o = "hello";
o = new Person();

// object 自带的方法
o.ToString();
o.GetType();
o.GetHashCode();
o.Equals(other);

所有类隐式继承 object

组合 vs 继承

继承很容易过度使用:

// ❌ 强行继承
public class FlyingDog : Dog { ... }    // 然后 SwimmingFlyingDog?

// ✅ 组合 + 接口
public interface ICanFly { void Fly(); }
public interface ICanSwim { void Swim(); }

public class Duck : Animal, ICanFly, ICanSwim { ... }

优先组合 + 接口——继承用在"是一个"非常明确的关系上(Cat 是 Animal),不要用来"借用功能"。

new 在继承层级中的几个意思

public new void Speak() { }        // 1. 隐藏父方法(不多态)
new Person()                        // 2. 创建实例(运算符)
where T : new()                     // 3. 泛型约束:T 必须有无参构造

不同上下文不同含义。

→ 下一篇 接口