C# 中的继承
在面向对象编程中,继承是类之间的一种关系。继承是一种将一个类的功能重用于另一个相关类的机制。
继承被称为“是一种”关系。在现实世界的例子中,客户是一个人。同样,学生也是一个人,员工也是一个人。他们都有一些共同点,例如,他们都有名字、中间名和姓氏。因此,为了将其转换为面向对象编程,我们可以创建具有名字、中间名和姓氏属性的 Person 类,并让 Customer、Student 和 Employee 类继承自 Person 类。这样我们就无需在所有类中创建相同的属性,并避免违反 DRY(不要重复自己)原则。
请注意,继承只能用于具有共同行为且完全可替代的相关类。请遵循里氏替换原则。

在 C# 中,使用 :
符号来让一个类继承另一个类。例如,以下 Employee
类在 C# 中继承自 Person
类。
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string GetFullName(){
return FirstName + " " + LastName;
}
}
class Employee : Person
{
public int EmployeeId { get; set; }
public string CompanyName { get; set; }
}
在上面的示例中,Person
类被称为基类或父类,而 Employee
类被称为派生类或子类。
Employee
类继承自 Person
类,因此它自动获得了 Person
类的所有公共成员。这意味着即使 Employee
类不包含 FirstName
、LastName
属性和 GetFullName()
方法,Employee
类的对象也将拥有 Person
类的所有属性和方法以及其自身的成员。
Employee emp = new Employee();
emp.FirstName = "Steve";
emp.LastName = "Jobs";
emp.EmployeeId = 1;
emp.CompanyName = "Apple";
var fullname = emp.GetFullName(); //Steve Jobs
请注意,C# 不允许一个类继承多个类。一个类只能通过接口实现多重继承。
访问修饰符在继承中的作用
访问修饰符在继承中扮演着重要角色。基类中每个成员的访问修饰符都会影响它们在派生类中的可访问性。
公共成员
基类的公共成员在派生类中是可访问的,并且也成为派生类对象的一部分。
class Person
{
public string FirstName { get; set; } // can be inherited
}
class Employee : Person
{
}
Employee emp = new Employee();
emp.FirstName = "Bill"; // valid
私有成员
基类的私有成员不能直接从派生类访问,也不能成为派生类对象的一部分。
class Person
{
private string FirstName { get; set; } // cannot be inherited
}
class Employee : Person
{
}
Employee emp = new Employee();
emp.FirstName; // Compile-time error
受保护成员
基类的受保护成员在派生类中是可访问的,但不能成为派生类对象的一部分。
class Person
{
protected string FirstName { get; set; }
}
class Employee : Person
{
public int GetName()
{
return this.FirstName;// valid
}
}
Employee emp = new Employee();
emp.GetName();// valid
emp.FirstName; // Compile-time error.
内部成员
内部成员在派生类中是可访问的,并且是派生类对象的一部分。
class Person
{
internal string FirstName { get; set; }
}
class Employee : Person
{
}
Employee emp = new Employee();
emp.Name= "Steve";// valid
构造函数
创建派生类对象时,会首先调用基类的构造函数,然后是派生类的构造函数。如果存在多级继承,则将首先调用第一个基类的构造函数,然后是第二个基类,依此类推。
class Person
{
public Person()
{
Console.WriteLine("Person Constructor");
}
}
class Employee : Person
{
public Employee()
{
Console.WriteLine("Employee Constructor");
}
}
Employee emp = new Employee();
Employee 构造函数
在派生类中使用 base
关键字访问基类的公共成员。例如,以下使用 :base()
调用基类的参数化构造函数。
class Person
{
public Person()
{
Console.WriteLine("Person Constructor");
}
public Person(string val)
{
Console.WriteLine(val);
}
}
class Employee : Person
{
public Employee() : base("Parameterized constructor of base class")
{
Console.WriteLine("Employee Constructor");
}
}
Employee emp = new Employee();
Employee 构造函数
对象初始化
您可以创建派生类的实例并将其赋值给基类或派生类的变量。实例的属性和方法取决于它被赋值的变量类型。这里,类型可以是类、接口或抽象类。
下表列出了根据变量类型和实例类型支持的成员。
实例变量 | 实例类型 | 实例成员 |
---|---|---|
基类型 | 基类型 | 基类型 |
基类型 | 派生类型 | 基类型 |
派生类型 | 派生类型 | 基类型和派生类型 |
以下程序演示了根据变量类型支持的成员
class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
class Employee : Person
{
public string CompanyName { get; set; }
public decimal Salary { get; set; }
}
public class Program
{
public static void Main()
{
Person per1 = new Person();
per1.Id = 1; //valid
per1.FirstName = "James"; //valid
per1.LastName = "Bond"; //valid
//per1.CompanyName; // not supported
//per1.Salary; // not supported
Person per2 = new Employee();
per2.Id = 2; //valid
per2.FirstName = "Bill"; //valid
per2.LastName = "Gates"; //valid
//per2.CompanyName; // not supported
//per2.Salary; // not supported
Employee emp = new Employee();
emp.Id = 1; //valid
emp.FirstName = "Steve";//valid
emp.LastName = "Jobs";//valid
emp.CompanyName = "XYZ"; //valid
emp.Salary = 10000; //valid
//invalid, can't assign base type to derived type
//Employee emp = new Person();
}
}
在上面的示例中,per2
的类型是 Person
,因此即使对象类型是 Employee
,它也只公开 Person
类型的公共属性。然而,emp
的类型是 Employee
,因此它公开了两个类的所有公共属性。请注意,基类型对象不能赋值给派生类型变量。
类型转换
基类型隐式转换为基类,而派生类型必须使用 as
运算符显式转换为基类。
public static void Display(Employee emp){
Console.WriteLine($"Name: {emp.FirstName} {emp.LastName}");
}
public static void Main()
{
Person per = new Employee();
per.FirstName="Steve";
per.LastName="Jobs";
//Cannot convert from Person to Employee implicitly
Display(per);//error
Display(per as Employee);//valid, explicit conversion
Employee emp = new Employee();
emp.FirstName = "Abdul";
emp.LastName = "Kalam";
Display(emp);//valid
}
公司名称
员工姓名:阿卜杜勒·卡拉姆
公司名称
继承类型
C# 中支持不同类型的继承,具体取决于类的继承方式。
单一继承
在单一继承中,只有一个派生类继承一个基类。

多级继承
在多级继承中,一个派生类继承自一个基类,然后该派生类又成为另一个派生类的基类。实际上,继承的级别没有限制,但应避免过度使用。

分层继承
在分层继承中,多个派生类继承自一个基类。

混合继承
混合继承是多级继承和分层继承的组合。

多重继承
在多重继承中,一个类继承自多个接口。请注意,C# 不支持继承多个基类。多重继承请使用接口。

重要事项
- 在 C# 中,三种类型可以参与继承:类、结构体和接口。
- 一个类只能继承一个类。它不能继承多个类。
- 一个类不能继承结构体。
- 一个类可以继承(实现)一个或多个接口。
- 一个结构体可以继承一个或多个接口。但是,它不能继承另一个结构体或类。
- 一个接口可以继承一个或多个接口,但不能继承类或结构体。
- 构造函数或析构函数不能被继承。