深入理解C#之继承

深入理解C#之继承

继承是面向对象编程中非常重要的一种机制,它可以使得我们代码重用性更高,更加简洁。在C#中,继承可以通过类之间的关系来实现(类之间的关系有继承、实现、组合等)。在本篇文章中,我们将学习C#中的继承机制,重点包括如下内容:

  • 继承的语法和基本概念
  • 虚方法和抽象类
  • 接口继承
  • 隐藏和重写方法
  • 继承链

继承的语法和基本概念

在C#中,使用:符号表示一个类继承自另一个类。例如,我们可以这样定义一个汽车类继承自交通工具类:

class Vehicle {
    // 交通工具类
}
class Car : Vehicle {
    // 汽车类继承自交通工具类
}

汽车类继承自交通工具类,那么汽车类就可以自动获得交通工具类中的所有属性和方法,无需重新定义。我们称交通工具类为父类或基类,汽车类为子类或派生类。

虚方法和抽象类

在父类中定义的方法,子类可以继承并使用。然而,在某些情况下,子类需要重写父类中的方法,例如:子类需要根据自己的特殊需求来重新实现某个方法。这就需要我们使用virtual关键字定义虚方法,例如:

class Vehicle {
    public virtual void Go() {
        Console.WriteLine("Vehicle is going.");
    }
}
class Car : Vehicle {
    public override void Go() {
        Console.WriteLine("Car is running.");
    }
}

在上面的代码中,我们定义了Vehicle类中的Go方法,使用了virtual关键字,表示这是一个虚方法,可以被子类重写。在Car类中,我们使用了override关键字来重写Go方法,并实现了自己的功能。

抽象类是父类中的一种特殊形式,它不能被直接实例化,只能被继承。抽象类中可以包含抽象方法,抽象方法必须被子类重写,否则子类也必须是抽象类。例如:

abstract class Vehicle {
    public abstract void Go();
}
class Car : Vehicle {
    public override void Go() {
        Console.WriteLine("Car is running.");
    }
}

接口继承

除了类继承,C#还提供了接口继承。一个接口定义了一组属性、方法和事件,但不包含实现。一个类可以实现一个或多个接口,以声明自己支持这些接口所定义的功能。例如:

interface IVehicle {
    void Go();
}
class Car : IVehicle {
    public void Go() {
        Console.WriteLine("Car is running.");
    }
}

上面的代码中,我们定义了一个IVehicle接口,它有一个Go方法。Car类实现了IVehicle接口,并实现了Go方法。

隐藏和重写方法

在C#中,派生类可以定义与基类同名的方法,这就涉及到隐藏和重写的概念。如果在派生类中定义了一个方法与基类中同名的方法,那么该方法就会隐藏基类中的方法。如果要调用基类中的方法,可以使用base关键字来指定。例如:

class Vehicle {
    public virtual void Go() {
        Console.WriteLine("Vehicle is going.");
    }
}
class Car : Vehicle {
    public new void Go() {
        Console.WriteLine("Car is running.");
    }
    public void GoBase() {
        // 调用基类的Go方法
        base.Go();
    }
}

在上面的代码中,我们定义了Car类的Go方法,它与基类中的Go方法同名。使用new关键字表示我们要隐藏基类中的方法。在Car类中,我们还定义了一个GoBase方法来调用基类的Go方法。

如果希望在派生类中重写基类的方法,需要使用override关键字。例如:

class Vehicle {
    public virtual void Go() {
        Console.WriteLine("Vehicle is going.");
    }
}
class Car : Vehicle {
    public override void Go() {
        Console.WriteLine("Car is running.");
        // 调用基类的Go方法
        base.Go();
    }
}

在上面的代码中,我们使用override关键字来重写基类的Go方法,并在子类中添加自己的实现。

继承链

在C#中,继承可以是多层嵌套的。例如:

class Vehicle {
    public virtual void Go() {
        Console.WriteLine("Vehicle is going.");
    }
}
class Car : Vehicle {
    public override void Go() {
        Console.WriteLine("Car is running.");
        base.Go();
    }
}
class Mustang : Car {
    public new void Go() {
        Console.WriteLine("Mustang is running.");
        base.Go();
    }
}

在上面的代码中,Mustang类继承自Car类,而Car类又继承自Vehicle类。因此,Mustang类不仅可以使用自己的方法,还可以使用父类和祖先类中的方法。必要时,还可以使用base关键字来访问特定层次的父类方法。

示例1:基类与派生类的方法重载

下面的代码演示了在基类和派生类中实现方法重载的方式:

using System;

namespace Demo1
{
    class Program
    {
        static void Main(string[] args)
        {
            // 创建一个Animal对象
            Animal animal1 = new Animal();
            // 调用Animal中的eat方法
            animal1.eat("grass");

            Console.WriteLine();

            // 创建一个Dog对象
            Dog dog1 = new Dog();
            // 调用Animal中的eat方法
            dog1.eat("bone");
            // 调用Dog中的eat方法
            dog1.eat("bone", 2);

            Console.ReadKey();
        }
    }

    class Animal
    {
        public void eat(string food)
        {
            Console.WriteLine("Animal is eating " + food);
        }

        public virtual void eat(string food, int count)
        {
            for (int i = 0; i < count; i++)
            {
                eat(food);
            }
        }
    }

    class Dog : Animal
    {
        public void eat(string food)
        {
            Console.WriteLine("Dog is eating " + food);
        }
    }

}

输出:

Animal is eating grass

Animal is eating bone
Dog is eating bone

在上面的代码中,我们定义了一个Animal类和一个Dog类。在Animal类中,我们定义了一个名为eat的方法,它接受一个参数food,输出一个信息。在Dog类中,我们也定义了一个名为eat的方法,但它与Animal类中的eat方法参数不同。我们还为Animal类和Dog类中的eat方法都添加了一个重载版本,其中Animal类中的版本是虚方法。

我们通过创建Animal和Dog对象来演示这些方法的使用。在Dog对象上调用eat方法时,如果传入一个参数,将会调用Dog类中的eat方法;如果传入两个参数,将会调用Animal类的虚方法。

示例2:多级继承示例

下面的代码演示了多级继承的示例,其中将定义三个类:

using System;

namespace Demo2
{
    class Program
    {
        static void Main(string[] args)
        {
            Employee emp1 = new Employee("Jack", "Xu", 2000);
            Manager mgr1 = new Manager("Bob", "Lee", 5000, "IT");
            Director dir1 = new Director("Amy", "Zhang", 10000, "Higher Education");

            emp1.print();
            mgr1.print();
            dir1.print();

            Console.ReadKey();
        }
    }

    class Employee
    {
        private string firstName;
        private string lastName;
        private decimal salary;

        public Employee(string fName, string lName, decimal sal)
        {
            firstName = fName;
            lastName = lName;
            salary = sal;
        }

        public void print()
        {
            Console.WriteLine("Employee Information: " + firstName + " " + lastName + ", Salary: " + salary);
        }
    }

    class Manager : Employee
    {
        private string department;

        public Manager(string fName, string lName, decimal sal, string dept) :
            base(fName, lName, sal)
        {
            department = dept;
        }

        public new void print()
        {
            Console.WriteLine("Manager Information: " + firstName + " " + lastName + ", Salary: " + salary + ", Department: " + department);
        }
    }

    class Director : Manager
    {
        private string institution;

        public Director(string fName, string lName, decimal sal, string dept) :
            base(fName, lName, sal, dept)
        {
            institution = "Our Institution";
        }

        public override void print()
        {
            Console.WriteLine("Director Information: " + firstName + " " + lastName + ", Salary: " + salary + ", Department: " + department + ", Institution: " + institution);
        }
    }
}

输出:

Employee Information: Jack Xu, Salary: 2000
Manager Information: Jack Xu, Salary: 5000, Department: IT
Director Information: Amy Zhang, Salary: 10000, Department: Higher Education, Institution: Our Institution

在上面的代码中,我们定义了三个类:Employee、Manager和Director。每个类都继承自前一个类,并添加了自己的成员。在Main方法中,我们创建了一个Employee、一个Manager和一个Director对象,分别调用它们的print方法。

我们可以看到,Employee类和Manager类中都定义了print方法,但Manager类中的版本是新方法。Director类重写了Manager类中的print方法,使用了override关键字。在Main方法中,我们创建了三个对象,并调用它们的print方法。在Director对象上调用print方法时,它将执行Director类中的版本,而不是Manager类中的版本。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:深入理解C#之继承 - Python技术站

(0)
上一篇 2023年5月15日
下一篇 2023年5月15日

相关文章

  • C#设置输入法实例分析

    C#设置输入法实例分析 概述 输入法是计算机上常用的工具,而在编写一些需要进行输入的程序时,需要对输入法进行设置。本文将详细讲解如何在C#程序中进行输入法设置。 获取当前输入法 在C#中,可以通过以下代码获取当前正在使用的输入法: System.Windows.Forms.InputLanguage currentInputLanguage = System…

    C# 2023年6月7日
    00
  • C#中使用@声明变量示例(逐字标识符)

    C#中使用@声明变量的方式又被称为逐字(verbatim)标识符。这种方式可以避免C#关键字与变量名冲突的问题,同时也支持在字符串中直接输出换行符和制表符等特殊字符,非常实用。下面我们详细讲解一下如何使用@声明变量。 基本语法 使用@声明变量的基本语法如下: @变量名 = 值 其中,@符号紧贴变量名,表示对变量名进行逐字标识符声明。 示例一 下面来看一个简单…

    C# 2023年5月15日
    00
  • 使用Log4net进行日志记录

    使用Log4net进行日志记录是一项非常重要的任务,因为它可以帮助开发者更好地了解应用程序的运行状态,检测并解决在调试和测试期间遇到的问题。下面就是关于如何使用Log4net进行日志记录的完整攻略: 步骤一:安装Log4net 首先,你需要在你的应用程序中下载并安装Log4net。你可以在NuGet管理器中搜索“log4net”,然后安装最新版本。 步骤二:…

    C# 2023年5月15日
    00
  • C#自定义鼠标拖拽Drag&Drop效果之基本原理及基本实现代码

    C#自定义鼠标拖拽Drag&Drop效果之基本原理 前言 在很多应用程序中,我们都需要使用拖拽效果来实现某些功能,比如拖拽文件到应用程序窗口中打开等。在C#中,我们可以利用Drag&Drop技术自定义鼠标拖拽的效果,本文将会详细讲解Drag&Drop技术的基本原理及基本实现方法。 基本原理 Drag&Drop技术,即拖放技术,…

    C# 2023年6月6日
    00
  • C#的字符串比较

    C#中,字符串比较有多种方式,最常用的有三种:使用“==”比较,使用Equals方法比较,使用Compare方法比较。 使用“==”比较字符串 在C#中,可以使用“==”符号来比较两个字符串是否相等,例如: string str1 = "hello"; string str2 = "world"; string str…

    C# 2023年6月1日
    00
  • .NET7使用HttpClient实现查询天气预报接口

    朋友做网站需要根据城市展示天气预报,找了一圈没有找到靠谱的接口,今天在中央气象台的官网查询某个城市找到了接口,先用postman试了一下居然可以使用,可以查询某个城市7天的天气预报等信息。但是查询编码是气象台自己的编码,在网上搜索了一下居然有这个编码。本文使用HttpClient方法查询这个接口。 天气接口 城市编码 HttpClient是.net core…

    C# 2023年4月19日
    00
  • C#调用Nero SDK刻录光盘的方法

    为了在C#中调用Nero SDK刻录光盘,我们可以按照以下步骤: 下载并安装Nero SDK以及Nero Burning ROM; 在Visual Studio中创建一个新的C#项目; 将Nero SDK中的NeroCOM.dll添加到你的项目引用中; 在你的代码中使用NeroCOM.dll来调用SDK的相关功能。 以下是示例代码的说明: 开始一个刻录进程 …

    C# 2023年6月6日
    00
  • C# 模式匹配完全指南

    C# 模式匹配完全指南 什么是 C# 模式匹配? C# 7.0 开始加入了一种新的特性,那就是模式匹配(Pattern Matching)。模式匹配的主要作用是用来匹配各种数据类型,从而简化我们的程序设计,并且让代码更加简洁易懂。 C# 模式匹配的类型 常量模式(Constant Patterns) 次类型模式(Type Patterns) 变量模式(Var…

    C# 2023年5月15日
    00
合作推广
合作推广
分享本页
返回顶部