404 Not Found

404 Not Found


nginx

继承

什么是继承

继承是面向对象编程的核心机制,允许一个类复用另一个类的成员并扩展新功能。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.Loadsealed 修饰后,从 JsonConfig 派生的类无法再重写 LoadFinalClasssealed 修饰后,任何类都无法继承它。

继承的构造函数链

创建派生类对象时,基类构造函数总是先于派生类构造函数执行。如果基类没有无参构造函数,派生类必须显式调用 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 用于类型检查,返回 boolas 用于安全类型转换,转换失败返回 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不能用于值类型。

📖 小节

📝 作业

  1. 定义一个 Employee 基类(含 NameSalary 属性),派生 Manager 类(额外含 Level 属性),在 Manager 构造函数中用 base 调用父类构造器。
  2. Employee 中定义 virtual void Work() 方法,在 Manager 中用 override 重写,并在重写方法里调用 base.Work()
  3. 创建一个 Employee[] 数组,包含 EmployeeManager 对象,用 is 运算符判断类型并输出不同信息。
  4. 重写 ManagerToString() 方法,返回包含 NameSalaryLevel 的字符串。
  5. 声明一个 sealedPayCalculator,尝试编写一个类继承它,观察编译错误。
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏