C# 中的继承:基类与派生类详解

开发 前端
在本文中,我们深入学习了 C# 中基类与派生类的概念,理解了继承的优势以及应用场景。通过丰富的实例和详细的注释,展示了如何在实际编程中使用继承来实现代码复用、封装和多态性。

在面向对象编程(OOP)中,继承是一个核心概念。它允许一个类(派生类)继承另一个类(基类)的属性和方法,从而实现代码的重用、封装和多态性。C# 作为一种面向对象的编程语言,提供了强大的继承机制。本文将详细介绍基类与派生类的应用特点和场景,并通过丰富的实例和注释加深理解。

继承的优势

代码复用

通过继承,派生类可以直接使用基类中已经定义的属性和方法,无需重复编写相同的代码,从而提高开发效率。

封装

基类可以将一些不需要外部访问的成员设为私有(private),只允许通过公共(public)方法来访问,从而隐藏实现细节,提高代码的安全性。

多态

通过虚方法(virtual)和抽象方法(abstract),基类可以定义可在派生类中重写(override)的方法,允许派生类表现出不同的行为。

继承的应用场景

建立类层次结构

当多个类共享相同的特性时,可以将这些共性抽象成一个基类,其他具有特定特性的类作为派生类。

实现接口替换原则

基类可以作为一个通用接口,允许在不改变外部代码的情况下替换和扩展内部实现。

设计模式的实现

很多设计模式(如工厂模式、策略模式等)都需要使用继承来实现特定的功能和逻辑。

实例详解

例1:基本继承与代码复用

namespace App05
{
    // 基类:车辆
    public class Vehicle
    {
        public string LicensePlate { get; set; }

        public void StartEngine()
        {
            Console.WriteLine("发动机已启动");
        }
    }

    // 派生类:汽车
    public class Car : Vehicle
    {
        public int NumberOfWheels { get; set; } = 4;

        public void Honk()
        {
            Console.WriteLine("汽车喇叭:嘟嘟!");
        }
    }
    internal class Program
    {
        static void Main(string[] args)
        {

            // 使用示例
            var car = new Car
            {
                LicensePlate = "粤A12345"
            };

            car.StartEngine(); // 继承自基类的方法
            car.Honk();        // 派生类的方法
            Console.WriteLine($"车牌号:{car.LicensePlate}");
            Console.WriteLine($"车轮数:{car.NumberOfWheels}");
        }
    }
}

图片图片

说明:

  • Car 类继承了 Vehicle 类,因此可以直接使用 Vehicle 中的属性和方法,如 LicensePlate 和 StartEngine()。
  • Car 类增加了自己的属性 NumberOfWheels 和方法 Honk()。

例2:方法重写与多态

namespace App05
{
    // 基类:动物
    public class Animal
    {
        public virtual void Speak()
        {
            Console.WriteLine("某种动物的叫声");
        }
    }

    // 派生类:狗
    public class Dog : Animal
    {
        public override void Speak()
        {
            Console.WriteLine("汪汪!");
        }
    }

    // 派生类:猫
    public class Cat : Animal
    {
        public override void Speak()
        {
            Console.WriteLine("喵喵!");
        }
    }
    internal class Program
    {
        static void Main(string[] args)
        {
            // 使用示例
            Animal animal;

            animal = new Dog();
            animal.Speak(); // 输出 "汪汪!"

            animal = new Cat();
            animal.Speak(); // 输出 "喵喵!"
        }
    }
}

图片图片

说明:

  • 在基类 Animal 中,Speak() 方法被声明为 virtual,表示它可以在派生类中被重写。
  • 在派生类 Dog 和 Cat 中,Speak() 方法使用 override 关键字进行重写,从而表现出不同的行为。
  • 通过将 animal 声明为 Animal 类型,可以实现多态性的效果。

例3:抽象类与多态

namespace App05
{
    // 抽象基类:形状
    public abstract class Shape
    {
        public abstract double Area();
    }

    // 派生类:圆形
    public class Circle : Shape
    {
        public double Radius { get; set; }

        public override double Area()
        {
            return Math.PI * Radius * Radius;
        }
    }

    // 派生类:矩形
    public class Rectangle : Shape
    {
        public double Width { get; set; }
        public double Height { get; set; }

        public override double Area()
        {
            return Width * Height;
        }
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            // 使用示例
            Shape circle = new Circle { Radius = 5 };
            Console.WriteLine($"圆的面积:{circle.Area()}");

            Shape rectangle = new Rectangle { Width = 4, Height = 6 };
            Console.WriteLine($"矩形的面积:{rectangle.Area()}");
        }
    }
}

图片图片

说明:

  • Shape 类被声明为抽象类,不能被实例化,只能被继承。
  • Area() 方法是一个抽象方法,必须在派生类中进行重写。
  • Circle 和 Rectangle 分别重写了 Area() 方法,实现了特定形状的面积计算。

例4:访问修饰符与封装

// 基类:账户
public class Account
{
    private decimal balance;

    public void Deposit(decimal amount)
    {
        balance += amount;
        Console.WriteLine($"存入:{amount},余额:{balance}");
    }

    public void Withdraw(decimal amount)
    {
        if (amount <= balance)
        {
            balance -= amount;
            Console.WriteLine($"取出:{amount},余额:{balance}");
        }
        else
        {
            Console.WriteLine("余额不足!");
        }
    }

    // 受保护的方法,可供派生类访问
    protected decimal GetBalance()
    {
        return balance;
    }
}

// 派生类:储蓄账户
public class SavingsAccount : Account
{
    private decimal interestRate = 0.01m; // 利率1%

    public void ApplyInterest()
    {
        decimal interest = GetBalance() * interestRate;
        Deposit(interest);
        Console.WriteLine($"已应用利息:{interest}");
    }
}

// 使用示例
var savings = new SavingsAccount();
savings.Deposit(1000);   // 存入初始金额
savings.ApplyInterest(); // 应用利息
savings.Withdraw(500);   // 取出部分金额

图片图片

说明:

  • Account 类的 balance 字段被声明为 private,只能在类内部访问。
  • 通过 protected 方法 GetBalance(),SavingsAccount 可以访问 balance 的值。
  • SavingsAccount 类新增了方法 ApplyInterest(),用于计算并应用利息。

例5:多级继承

namespace App05
{
    // 基类:电子产品
    public class Electronic
    {
        public void TurnOn()
        {
            Console.WriteLine("设备已打开");
        }
    }

    // 派生类:电脑
    public class Computer : Electronic
    {
        public void Boot()
        {
            Console.WriteLine("电脑正在启动");
        }
    }

    // 派生类:笔记本电脑
    public class Laptop : Computer
    {
        public void Fold()
        {
            Console.WriteLine("笔记本电脑可以折叠");
        }
    }
    internal class Program
    {
        static void Main(string[] args)
        {
            // 使用示例
            var laptop = new Laptop();
            laptop.TurnOn(); // 继承自 Electronic
            laptop.Boot();   // 继承自 Computer
            laptop.Fold();   // 自身的方法
        }
    }
}

图片图片

说明:

  • 通过多级继承,Laptop 类继承了 Computer 和 Electronic 类的属性和方法。

四、总结

在本文中,我们深入学习了 C# 中基类与派生类的概念,理解了继承的优势以及应用场景。通过丰富的实例和详细的注释,展示了如何在实际编程中使用继承来实现代码复用、封装和多态性。

在设计自己的类层次结构时,应考虑如何有效地利用继承来优化代码的结构和可重用性。然而,需要注意的是,过度使用继承可能会导致代码的复杂性增加,应根据实际需求进行合理设计。

建议:

  • 在使用继承时,优先考虑类之间是否存在显式的“是一个”(is-a)关系。
  • 如果只是需要某些功能,而不需要继承整个类,可以考虑使用接口(interface)或组合(composition)。
责任编辑:武晓燕 来源: 技术老小子
相关推荐

2011-06-01 10:19:41

基类对象派生类对象

2009-07-28 17:38:02

ASP.NET多态抽象基类

2024-10-09 07:59:10

C#接口信息

2010-01-15 18:35:25

C++的类

2009-09-03 13:14:55

C#构造函数C#析构函数

2010-01-21 13:33:44

C++基类

2009-09-17 16:34:24

C#组件类

2009-09-04 11:15:07

选择C#构造函数

2009-08-28 14:09:19

C#静态类

2009-08-18 12:23:38

2009-07-30 18:20:21

C#继承

2010-01-21 13:48:30

C++基类

2010-07-12 09:07:30

C#

2009-11-09 16:49:53

Visual Stud

2009-08-03 18:12:31

C#抽象类

2010-01-27 10:22:53

C++基类

2009-08-05 14:54:09

VB调用C#类库

2009-09-18 13:40:40

继承关系

2009-08-10 10:37:17

C#类与结构

2009-08-21 14:16:35

C# New关键字
点赞
收藏

51CTO技术栈公众号