C# 继承

C# 继承是一种重用机制,通过父子关系,一个类的成员可以被另一个类访问。C# 编程语言中继承的语法如下所示。

<Access modifier> Class <child class> : <parent class>

Class A // A is a parent class.
{
    Class members
}
Class B: Class A // B is a child class
{
    Members of A can be accessed here
}

父类也称为基类或超类,而子类也称为派生类或子类。

C# 继承示例

继承机制允许子类访问父类的成员(除了其私有成员),就像它是该成员的所有者一样。

要在 C# 中实现继承,父类构造函数必须对子类可访问。这意味着我们必须将父构造函数定义为 public,因为默认情况下,未定义任何修饰符的构造函数是 private 的。

让我们看一个实现继承的示例。

using System;

namespace CSharp_Tutorial
{
    class Program
    {
        public Program()
        {
            Console.WriteLine("This is parent class constructor");
        }
        public void Test1()
        {
            Console.WriteLine("Test1 method");
        }
        public void Test2()
        {
            Console.WriteLine("Test2 method");
        }
    }
}
C# Inheritance 1
using System;
using System.Collections.Generic;
using System.Text;

namespace CSharp_Tutorial
{
    class Program1:Program
    {
        public Program1()
        {
            Console.WriteLine("This is child class constructor");
        }
        void Test3()
        {
            Console.WriteLine("Test3 method");
        }
        static void Main()
        {
            Program1 p = new Program1();
            p.Test1(); p.Test2(); p.Test3();
            Console.ReadLine();

        }
    }
}
Access Methods

在这个继承示例中,Program 是一个父类,其中创建了一个构造函数以及两个方法,Test1() 和 Test2()。接下来,Program1 也是一个包含构造函数和方法 Test3() 的类。但在 cProgram1 中,Program 的成员也被继承了。

现在,当我们尝试执行 Program1 时,编译器首先调用子类中的构造函数。同时,子构造函数隐式调用父构造函数以初始化父变量,以便子类可以使用父成员。

因此,C# 继承的执行顺序是父类构造函数,然后是子构造函数,接着是子类继承的方法和在其自身中定义的方法。

注意:如果父类也有一个父类,为子类创建的实例将调用其构造函数。同时,其构造函数将调用此父类的父构造函数,依此类推。执行从顶层的父类开始,向下到子类。

请记住,父类不能访问子类自身纯粹定义的子成员。

在父类中创建子类的引用

C# 父类不能访问子成员,但我们可以在继承中在父类中创建子类的引用。

我们之前已经了解到,引用只是实例的指针变量,即引用没有分配任何内存。但是,它指向实例的内存。即使我们可以创建子类的引用,使用该父类引用,我们也不能访问子类中纯粹定义的子成员。

using System;

namespace CSharp_Tutorial
{
    class Program
    {
        public Program()
        {
            Console.WriteLine("This is parent class constructor");
        }
        public void Test1()
        {
            Console.WriteLine("Test1 method");
        }
        public void Test2()
        {
            Console.WriteLine("Test2 method");
        }
        static void Main()
        {
            Program p;
            Program1 p1 = new Program1();
            p = p1;
            p.Test1(); p.Test2();
            Console.ReadLine();
        }
    }
}
Create a reference to child class

这里,p 是 C# 继承程序的一个局部变量,它是一个父类。接下来,p 用 Program1 的实例 p1 初始化,Program1 是一个子类。

现在 p 是一个未初始化且未分配任何内存的父变量,而 p1 是一个子实例。显然,实例总是会分配内存。

p 用 p1 初始化。这意味着 p 是实例 p1 的引用,通过它我们正在访问父类成员,但无法访问纯粹的子成员。

最后,我们可以说,在不为父类创建实例的情况下,我们可以使用指向子实例的引用来访问父成员。

对象类位于父层次结构的顶部

库中或我们自己定义的每个类都将有一个父类,即 System 命名空间中的 Object。

Object 类的成员是 Equals、GetHashCode、GetType、ToString。

因此,Object 的所有成员都可以从任何地方访问。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp3
{
  class Program1:Program
  {
    void Test3()
    {
      Console.WriteLine("Test3 method");
    }
    static void Main()
    {
      Object o = new Object();
      Console.WriteLine(o.GetType());
      Program p = new Program();
      Console.WriteLine(p.GetType());
      Program1 p1 = new Program1();
      Console.WriteLine(p1.GetType());
      Console.ReadLine();

    }
  }
}
Inheritance 4

GetType 是一个 Object 成员,可以从任何类访问。GetType 将获取特定实例的完全限定名。

这里,o 是 System 命名空间中对象的一个实例。这意味着 System.Object。接下来,p 和 p1 分别是 ConsoleApp3 命名空间中 Program 和 Program1 的实例,因此

ConsoleApp3.Program

ConsoleApp3.Program1

C# 中的继承类型

根据子类拥有的直接父类的数量或父类拥有的直接子类的数量,继承有两种类型。

  • 单继承
  • 多继承

如果一个类有一个直接父类,那么它属于单继承。相反,一个类有多个直接父类则属于多继承。然而,C# 只支持单继承,不支持类的多继承。

父类构造函数是带参数的构造函数吗?

正如我们已经知道的,当创建子类实例时,子构造函数会隐式调用父构造函数。这只发生在父构造函数是无参数的情况下。

但是,如果 C# 父类构造函数带参数,子构造函数就不能调用父类的构造函数。为了克服这个问题,我们应该从子类构造函数中显式调用它,并通过使用  base  关键字传递参数。

using System;

namespace CSharp_Tutorial
{
    class Program
    {
        public Program(int a)
        {
            Console.WriteLine("Constructor of class Program is called: " + a);
        }
        public void Test1()
        {
            Console.WriteLine("Test1 method");
        }
        public void Test2()
        {
            Console.WriteLine("Test2 method");
        }
    }
parameterized constructor
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp3
{
  class Program1:Program
  {
    public Program1(int b):base(b)
    {
      Console.WriteLine("Constructor of class Program1 is called");
    }
    void Test3()
    {
      Console.WriteLine("Test3 method");
    }
    static void Main()
    {
      Program1 p1 = new Program1(10);
      Console.ReadLine();
    }
  }
}
Inheritance Example

在子类 Program1 中,关键字 base 代表父类。

当实例 p1 创建时,它会调用 Program1 构造函数,然后通过传递参数 b(值为 10)调用 Program 构造函数。

这里,变量 b 也可以在子类中访问。

在实时环境中实现 C# 继承

在实时环境中,我们会遇到“实体”这个词,它不过是一个对象,以及关于该对象收集的数据。实体总是与特定属性相关联。

应用程序可以通过在不同实体之间建立关系来创建。例如,如果我们需要为学校开发一个应用程序,

学生、教学人员、非教学人员和临时人员通常是实体。

为每个实体维护一些常见属性。

Inheritance 7

ID、姓名、地址和电话是所有实体的共同属性。因此,通过这四个实体,我们可以创建一个名为 Person 的类,并使其成为所有这些实体的父类。

同样,对于员工,薪水和职位将是属性。Staff 可以用作教学和非教学人员的父类。

上图描述了在开发学校应用程序时如何实现继承。

分类 C#