面向对象3大特性之一:继承

Posted CS讷于言而敏于行

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向对象3大特性之一:继承相关的知识,希望对你有一定的参考价值。

继承

继承表示一个类型(子类)派生自(继承于)一个基类型(父类),该类型将拥有基类型的所有成员字段和函数(不包括构造函数和析构函数)。

注意:

  • 派生类继承基类的所有成员,不管是public、private、protected还是其他的,不管是静态的还是非静态的;但是,虽然派生类继承类基类所有的成员,基类却只能访问由public和protected修饰的成员(派生类继承了基类所有的字段,但是只能访问基类中public和protected修饰的成员)
 1     class Person
 2     {
 3         private string name = "张三";
 4         protected int age = 20;
 5         public bool gender = true;
 6 
 7         public void ShowInfo_Person()
 8         {
 9             Console.WriteLine(this.name + ":" + this.age + ":" + this.gender);
10         }
11     }
12 
13     class Chinese : Person
14     {
15         public void ShowInfo_Chinese()
16         {
17             Chinese chinese = new Chinese();
18             Console.WriteLine(chinese.age);
19             Console.WriteLine(chinese.gender);
20             //Console.WriteLine(chinese.name);//由于基类中name用private修饰,所以在派生类中无法访问
21         }
22     }
23 
24     class Program
25     {
26         static void Main(string[] args)
27         {
28             Chinese chinese = new Chinese();
29             chinese.ShowInfo_Person();//输出结果:张三:20:True  此处通过派生类对象chinese可以调用基类中的ShowInfo_Person()方法,可以说明派生类也继承了private修饰的name字段
30             Console.ReadKey();
31         }
32     }
  • 派生类(子类)只能有一个直接基类(父类);但是继承是可以传递的,例如ClassB派生自ClassA,同时ClassC派生自ClassB,那么ClassC会继承ClassB和ClassA中声明的成员。
 1     class Animal
 2     {
 3         public void Method_Animal()
 4         {
 5             Console.WriteLine("Animal:---------------");
 6         }
 7     }
 8 
 9     class Dog : Animal
10     {
11         public void Method_Dog()
12         {
13             Console.WriteLine("Dog:***************");
14         }
15     }
16 
17     class ErHa : Dog
18     {
19         public void Method_ErHa()
20         {
21             Console.WriteLine("ErHa:...............");
22         }
23     }
24 
25     class Program
26     {
27         static void Main(string[] args)
28         {
29             ErHa eh = new ErHa();
30             eh.Method_Animal();
31             eh.Method_Dog();
32             eh.Method_ErHa();
33             Console.ReadKey();
34         }
35     }
  • C#不支持多重继承,派生类只能有一个直接基类,但是可以实现多个接口,并通过实现多个接口达到多重继承的目的
 1     interface IAnimal
 2     {
 3         void Method_Animal();
 4     }
 5 
 6     interface IDog
 7     {
 8         void Method_Dog();
 9     }
10     //实现多重继承
11     class ErHa : IAnimal, IDog
12     {
13         public void Method_ErHa()
14         {
15             Console.WriteLine("ErHa:...............");
16         }
17 
18         public void Method_Animal()
19         {
20             Console.WriteLine("Animal:************");
21         }
22 
23         public void Method_Dog()
24         {
25             Console.WriteLine("Dog:---------------");
26         }
27     }
28 
29     class Program
30     {
31         static void Main(string[] args)
32         {
33             ErHa eh = new ErHa();
34             eh.Method_Animal();
35             eh.Method_Dog();
36             eh.Method_ErHa();
37             Console.ReadKey();
38         }
39     }
  • 结构不支持继承
  • 派生类是对基类的扩展,派生类可以对基类进行成员的添加、重写、覆盖操作

构造函数

  • 派生类无法继承基类的构造函数
  • 当调用派生类的构造函数时,默认先调用基类的无参构造函数,当基类没有无参构造,需要派生类通过base关键字指定要调用的基类构造函数
 1     class Person
 2     {
 3         public Person()
4 { 5 Console.WriteLine("父类的无参构造函数被调用"); 6 } 7 } 8 9 class Student:Person
10 { 11 public Student() 12 { 13 Console.WriteLine("子类的无参构造函数被调用"); 14 } 15 } 16 17 class Program 18 { 19 static void Main(string[] args) 20 { 21 Student stu = new Student(); 22 Console.ReadKey(); 23 } 24 }

 执行结果:

 当基类中不存在无参的构造函数时,需要通过base关键字派生类指定其要调用的基类的构造函数

 1     class Person
 2     {
 3         public Person(string name)
 4         {
 5             Console.WriteLine(name);
 6         }
 7     }
 8 
 9     class Student : Person
10     {
11         public Student()
12         {
13             Console.WriteLine();
14         }
15     }
16 
17     class Program
18     {
19         static void Main(string[] args)
20         {
21             Student stu = new Student();
22             Console.ReadKey();
23         }
24     }

 以上代码执行时会出现以下错误:

如果我们想要使派生类调用基类的有参构造函数,而不是无参构造函数,就可以在派生类中通过base为其要调用的基类构造函数

 1     class Person
 2     {
 3         public Person(string name)
 4         {
 5             Console.WriteLine("姓名:"+name);
 6         }
 7     }
 8 
 9     class Student : Person
10     {
11         public Student(string name, string num)
12             : base(name)
13         {
14             Console.WriteLine("学号:"+num);
15         }
16     }
17 
18     class Program
19     {
20         static void Main(string[] args)
21         {
22             Student stu = new Student("张三", "0002");
23             Console.ReadKey();
24         }
25     }

接下来我们通过以下代码,了解一下子类对象的初始化过程

 1     class Person
 2     {
 3         public string name = "默认值:张三";
 4         public string gender = "默认值:男";
 5         public Person(string name, string gender)
 6         {
 7             this.name = name;
 8             this.gender = gender;
 9         }
10     }
11 
12     class Student : Person
13     {
14         public string num = "默认值:0002";
15         public Student(string name, string gender, string num)
16             : base(name, gender)
17         {
18             this.num = num;
19         }
20     }
21 
22     class Program
23     {
24         static void Main(string[] args)
25         {
26             Student stu = new Student("李四", "", "0004");
27             Console.WriteLine(stu.name);
28             Console.WriteLine(stu.gender);
29             Console.WriteLine(stu.num);
30             Console.ReadKey();
31         }
32     }

 当在Main方法中实例化Student的对象时,首先在内存中分配了空间,内存中的初始状态如下图:

 调用派生类的构造函数,首先会调用基类的构造函数,由于我们在派生类Student中通过base关键字指定了派生类要调用的基类构造函数为public Person(string name,string gender),所以首先会用传入的参数替换掉基类中成员的默认值,执行完成后,内存中的情况如下:

 执行完指定的基类构造函数后,执行派生类自身的构造函数,执行完成后,内存中的情况如下:

至此,派生类对象实例化完成。

以上是关于面向对象3大特性之一:继承的主要内容,如果未能解决你的问题,请参考以下文章

Python面向对象特性 - 继承

Java面向对象(OOP)--面向对象三大特性之一: 继承(继承Object类Super关键字方法重写)

PHP学习笔记之继承(面向对象三大特性之一)

python面向对象三大特性之一继承

面向对象的三大特性之一:继承

面向对象编程继承