一、继承的基本概念
继承是面向对象编程的三大特性之一(封装、继承、多态),它允许我们基于现有类创建新类,实现代码的重用和扩展。
1. 基本语法
// 基类(父类)
public class Animal
{
public string Name { get; set; }
public void Eat()
{
Console.WriteLine($"{Name}在吃东西");
}
}
// 派生类(子类)
public class Dog : Animal // 使用冒号表示继承
{
public void Bark()
{
Console.WriteLine($"{Name}在汪汪叫");
}
}
2. 继承的特点
- 子类继承父类的所有公共(public)和保护(protected)成员
- 子类可以添加新成员(扩展)
- 子类可以修改继承的成员(重写)
- C#只支持单继承(一个类只能直接继承一个父类)
二、继承的使用
1. 基本使用示例
Dog myDog = new Dog();
myDog.Name = "阿黄"; // 继承自Animal的属性
myDog.Eat(); // 继承自Animal的方法
myDog.Bark(); // Dog类自身的方法
2. 构造函数继承
子类构造函数可以通过base
关键字调用父类构造函数:
public class Vehicle
{
public string Brand { get; }
public Vehicle(string brand)
{
Brand = brand;
}
}
public class Car : Vehicle
{
public int Wheels { get; }
public Car(string brand, int wheels) : base(brand)
{
Wheels = wheels;
}
}
// 使用
Car myCar = new Car("丰田", 4);
Console.WriteLine($"品牌:{myCar.Brand},轮子数:{myCar.Wheels}");
三、多态的实现
多态是指同一操作作用于不同对象时,可以有不同的解释和执行结果。C#主要通过以下方式实现多态:
1. 虚方法(virtual)和重写(override)
public class Shape
{
public virtual void Draw() // 虚方法
{
Console.WriteLine("绘制基本形状");
}
}
public class Circle : Shape
{
public override void Draw() // 重写方法
{
Console.WriteLine("绘制圆形");
}
}
public class Rectangle : Shape
{
public override void Draw()
{
Console.WriteLine("绘制矩形");
}
}
// 使用多态
Shape[] shapes = new Shape[3];
shapes[0] = new Shape();
shapes[1] = new Circle();
shapes[2] = new Rectangle();
foreach (Shape shape in shapes)
{
shape.Draw(); // 根据实际对象类型调用相应方法
}
2. 抽象类(abstract)和抽象方法
public abstract class Animal
{
public abstract void MakeSound(); // 抽象方法,无实现
public void Sleep()
{
Console.WriteLine("动物在睡觉");
}
}
public class Cat : Animal
{
public override void MakeSound()
{
Console.WriteLine("喵喵叫");
}
}
public class Duck : Animal
{
public override void MakeSound()
{
Console.WriteLine("嘎嘎叫");
}
}
// 使用
Animal myCat = new Cat();
Animal myDuck = new Duck();
myCat.MakeSound(); // 输出"喵喵叫"
myDuck.MakeSound(); // 输出"嘎嘎叫"
3. 隐藏方法(new)
当不希望重写父类方法而是完全隐藏它时,可以使用new
关键字:
public class BaseClass
{
public void Show()
{
Console.WriteLine("基类方法");
}
}
public class DerivedClass : BaseClass
{
public new void Show()
{
Console.WriteLine("派生类方法");
}
}
// 使用
BaseClass obj1 = new DerivedClass();
obj1.Show(); // 输出"基类方法"
DerivedClass obj2 = new DerivedClass();
obj2.Show(); // 输出"派生类方法"
四、密封类(sealed)和密封方法
1. 密封类
阻止其他类继承该类:
public sealed class FinalClass
{
// 类成员
}
// 以下代码会报错
// public class TryDerive : FinalClass {}
2. 密封方法
在重写方法上使用sealed
,阻止派生类进一步重写该方法:
public class A
{
public virtual void Method() {}
}
public class B : A
{
public sealed override void Method() {}
}
public class C : B
{
// 以下代码会报错
// public override void Method() {}
}
五、is和as运算符
1. is运算符
检查对象是否与给定类型兼容:
Animal animal = new Cat();
if (animal is Cat)
{
Console.WriteLine("这是一只猫");
}
2. as运算符
尝试将对象转换为指定类型,失败则返回null:
Animal animal = new Duck();
Duck duck = animal as Duck;
if (duck != null)
{
duck.MakeSound();
}
六、综合应用示例
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
// 创建员工集合
List<Employee> employees = new List<Employee>
{
new Manager("张经理", 15000, 5000),
new Developer("李开发", 12000, "C#"),
new SalesPerson("王销售", 8000, 0.1)
};
// 多态调用
foreach (var emp in employees)
{
emp.DisplayInfo();
Console.WriteLine($"月收入:{emp.CalculatePay()}\n");
}
}
}
// 基类
public abstract class Employee
{
public string Name { get; }
public decimal BaseSalary { get; }
protected Employee(string name, decimal baseSalary)
{
Name = name;
BaseSalary = baseSalary;
}
public abstract decimal CalculatePay();
public virtual void DisplayInfo()
{
Console.WriteLine($"员工姓名:{Name}");
Console.WriteLine($"基本工资:{BaseSalary}");
}
}
// 派生类:经理
public class Manager : Employee
{
public decimal Bonus { get; }
public Manager(string name, decimal baseSalary, decimal bonus)
: base(name, baseSalary)
{
Bonus = bonus;
}
public override decimal CalculatePay()
{
return BaseSalary + Bonus;
}
public override void DisplayInfo()
{
base.DisplayInfo();
Console.WriteLine($"职位:经理,奖金:{Bonus}");
}
}
// 派生类:开发人员
public class Developer : Employee
{
public string Language { get; }
public Developer(string name, decimal baseSalary, string language)
: base(name, baseSalary)
{
Language = language;
}
public override decimal CalculatePay()
{
return BaseSalary * 1.1m; // 开发人员有10%的技术津贴
}
public override void DisplayInfo()
{
base.DisplayInfo();
Console.WriteLine($"职位:开发人员,主攻语言:{Language}");
}
}
// 派生类:销售人员
public class SalesPerson : Employee
{
public double CommissionRate { get; }
public SalesPerson(string name, decimal baseSalary, double rate)
: base(name, baseSalary)
{
CommissionRate = rate;
}
public override decimal CalculatePay()
{
// 假设销售额为100000来计算佣金
decimal commission = 100000 * (decimal)CommissionRate;
return BaseSalary + commission;
}
public override void DisplayInfo()
{
base.DisplayInfo();
Console.WriteLine($"职位:销售人员,佣金比例:{CommissionRate:P0}");
}
}
七、继承与多态的最佳实践
- 合理使用继承:只有在”是一个”关系成立时才使用继承
- 优先使用组合:当”有一个”关系更合适时,使用组合而非继承
- 遵循LSP原则:里氏替换原则,子类应该能够替换父类
- 慎用方法隐藏:使用
new
关键字隐藏方法通常不是好的设计 - 合理设计抽象:将通用行为放在基类,变化行为通过虚方法或抽象方法实现
- 避免过深继承:继承层次不宜过深,通常不超过3-4层
继承与多态是C#面向对象编程的核心概念,合理运用这些特性可以创建出灵活、可扩展的应用程序架构。通过继承实现代码重用,通过多态实现接口统一而行为多样,这是构建复杂系统的有力工具。