C#继承和虚方法virtual

C#继承和虚方法virtual

在C#中,继承是一个重要的面向对象编程(OOP)特性,它允许您创建一个类(称为派生类或子类),该类继承另一个类(称为基类或父类)的属性和方法。继承提供了代码复用的机制,使得您可以扩展已有的类来创建新的类,同时保持原有类的功能。

继承的基本概念

  1. 基类(Base Class):这是被继承的类,也称为父类或超类。基类可以定义一些通用的行为和状态。
  2. 派生类(Derived Class):这是继承基类的类,也称为子类。派生类可以从基类继承成员,并可以添加新的成员或覆盖已有的成员。

继承的语法

在C#中,继承是通过在类定义后面加上冒号 : 并指定要继承的基类来实现的。

public class Animal  // 基类
{
    public virtual void MakeSound()  // 虚方法
    {
        Console.WriteLine("Some sound");
    }
}

public class Dog : Animal  // 派生类
{
    public override void MakeSound()  // 覆盖基类的方法
    {
        Console.WriteLine("Woof!");
    }
}

继承的关键概念

访问修饰符
  • public:公开的,可以从任何地方访问。
  • protected:受保护的,只能从派生类访问。
  • internal:在同一程序集中可见。
  • private:私有的,只能在定义它的类内部访问。

基类中的成员可以被派生类访问,但受限于成员的访问级别。例如,private 成员无法被派生类访问。

虚方法与覆盖
  • 虚方法(Virtual Methods):在基类中定义,可以被派生类覆盖。使用 virtual 关键字定义。
  • 覆盖方法(Override Methods):在派生类中重写基类的虚方法,以提供不同的实现。使用 override 关键字定义。
public class BaseClass
{
    public virtual void VirtualMethod()
    {
        Console.WriteLine("BaseClass's VirtualMethod");
    }
}

public class DerivedClass : BaseClass
{
    public override void VirtualMethod()
    {
        Console.WriteLine("DerivedClass's VirtualMethod");
    }
}

虚方法(Virtual Methods)

虚方法是一个在基类中定义的方法,它可以被派生类重写(override)。虚方法使用 virtual 关键字来定义。虚方法的主要目的是为了实现多态性,即让派生类能够提供自己的实现方式。

定义虚方法

虚方法的定义格式如下:

csharp深色版本

public virtual returnType methodName([parameters])
{
    // 方法体
}
示例

假设我们有一个 Animal 类,其中定义了一个虚方法 MakeSound

csharp深色版本

public class Animal
{
    public virtual void MakeSound()
    {
        Console.WriteLine("The animal makes a sound.");
    }
}

在这个例子中,MakeSound 方法是一个虚方法,它提供了一个默认的行为,即打印出一条消息。派生类可以选择覆盖这个方法来提供特定的行为。

覆盖方法(Overridden Methods)

覆盖方法是在派生类中重新定义基类的虚方法的过程。覆盖方法使用 override 关键字来定义,并且必须完全匹配基类中虚方法的签名(包括返回类型和参数列表)。

定义覆盖方法

覆盖方法的定义格式如下:

public override returnType methodName([parameters])
{
    // 方法体
}
示例

接下来,我们创建一个 Dog 类,它继承自 Animal 类,并覆盖了 MakeSound 方法:

public class Dog : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine("The dog says woof!");
    }
}

在这个例子中,Dog 类覆盖了 Animal 类中的 MakeSound 方法,提供了不同的实现。

使用虚方法和覆盖方法

当您调用一个虚方法时,实际调用的是对象的实际类型所定义的方法。这就是多态性的体现。即使您使用基类的引用来指向派生类的对象,调用的仍然是派生类中覆盖的方法。

示例

考虑以下代码:

public class Program
{
    public static void Main(string[] args)
    {
        Animal myDog = new Dog();  // 基类引用指向派生类对象
        Animal myCat = new Animal();  // 基类引用指向基类对象

        myDog.MakeSound();  // 输出 "The dog says woof!"
        myCat.MakeSound();  // 输出 "The animal makes a sound."
    }
}

在这个例子中,myDog 是一个 Animal 类型的引用,但它指向的是 Dog 类的对象。因此,当调用 MakeSound 方法时,实际上调用的是 Dog 类中覆盖的方法。

虚方法与覆盖方法的区别

  • 虚方法:定义在基类中,可以被派生类覆盖。如果没有被派生类覆盖,则使用基类中的实现。
  • 覆盖方法:定义在派生类中,用于替代基类中的虚方法实现。必须与基类中的虚方法完全匹配。

注意事项

  • 不可覆盖的方法:如果一个方法被声明为 sealed,则不能被派生类覆盖。
  • 必须覆盖的方法:如果一个方法被声明为 abstract,则必须在派生类中覆盖它。
  • 类型安全性:在使用虚方法和覆盖方法时,应确保类型的安全性。例如,不能将派生类的引用强制转换为基类,然后调用派生类特有的方法。
密封方法与密封类
  • 密封方法(Sealed Methods):使用 sealed 关键字定义的方法不能被派生类覆盖。
  • 密封类(Sealed Classes):使用 sealed 关键字定义的类不能被继承。

csharp深色版本

public sealed class SealedClass
{
    // 不能被继承
}

public class BaseClass
{
    public virtual void VirtualMethod() { }
    public sealed void SealedMethod() { } // 不能被覆盖
}
基类构造函数的调用

在派生类的构造函数中,必须显式地调用基类的一个构造函数。这通常是通过在派生类构造函数中使用 base 关键字来完成的。

public class BaseClass
{
    public BaseClass()
    {
        Console.WriteLine("BaseClass Constructor");
    }
}

public class DerivedClass : BaseClass
{
    public DerivedClass()
    {
        // 基类构造函数会在此处被自动调用
        Console.WriteLine("DerivedClass Constructor");
    }
}

继承的注意事项

  1. 单继承:C# 支持单继承,即一个类只能直接继承一个基类。
  2. 多重继承:虽然C#不支持多重继承(一个类继承多个基类),但它通过接口来实现多接口继承。
  3. 继承层次:继承可以形成层次结构,一个类可以继承另一个派生类。

示例

下面是一个简单的继承示例,展示了如何使用继承来创建类层次结构。

public class Animal
{
    public virtual void Sound()
    {
        Console.WriteLine("Animal makes a sound.");
    }
}

public class Dog : Animal
{
    public override void Sound()
    {
        Console.WriteLine("Dog barks.");
    }
}

public class Cat : Animal
{
    public override void Sound()
    {
        Console.WriteLine("Cat meows.");
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        Animal myDog = new Dog();
        Animal myCat = new Cat();

        myDog.Sound(); // 输出 "Dog barks."
        myCat.Sound(); // 输出 "Cat meows."
    }
}

通过这个例子,您可以看到如何定义基类 Animal 和两个派生类 DogCat,以及如何在派生类中覆盖基类的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值