面向对象编程(第2天):多态性和继承(继承)

介绍 在本文的第一部分中,我们了解了方法重载的不同场景,并做了很多有趣的操作。在本系列的第2部分,我的文章将只关注OOP中的继承概念。让我们用一些要点来定义继承: 路线图 我们仍然坚持在开始学习OOP系列之前定义的路线图: 潜水在OOP(第一天):多态和继承(早期绑定/编译时多态)潜水在OOP(第二天):多态和继承(继承)潜水OOP(第三天):多态和继承(动态绑定/运行时多态)潜水在OOP(第四天):多态和继承(关于Abstarct类在c#中)潜水在OOP(第五天):都是用c#访问修饰符(公共/私人/保护/内部/密封/常量/只读的字段)潜水OOP(6天):理解枚举在c#中(一个实际的方法)深入OOP(第七天):用c#属性(一个实际的方法)深入OOP(8天):用c#索引器(一个实际的方法)潜水印锑OOP(9天):了解c#事件(Insight)学习c#(第十天):代表在c#中(一个实际的方法)学习c#(11天):c#事件(一个实际的方法) 继承在行动 好的。让我们动手做一下。创建一个控制台应用程序并将其命名为InheritanceAndPolymorphism。添加一个名为ClassA的类和一个名为ClassB的类,代码如下: 注意:每一个代码片段写本文是尝试和测试。 隐藏,复制Code

ClassA:

   class ClassA
     {
        
     }

ClassB:

    class ClassB
    {
        public int x = 100;
        public void Display1()
        {
            Console.WriteLine("ClassB Display1");
        }
        public void Display2()
        {
            Console.WriteLine("ClassB Display2");
        }
    }

我们看到类ClassA是空的,于是我们在类ClassB中添加了两个方法,即Display1和Display2。我们还有一个变量x声明并定义为值100。 现在在主程序的方法。cs,写以下代码: Program.cs 隐藏,复制Code

class Program
  {
      static void Main(string[] args)
      {

          ClassA a = new ClassA();
          a.Display1();
      }
  }

如果我们运行代码,会立即导致编译时错误。 错误:“InheritanceAndPolymorphism。ClassA'不包含'Display1'的定义,也没有扩展方法'Display1'接受类型'InheritanceAndPolymorphism的第一个参数。可以找到ClassA'(您是否丢失了using指令或汇编引用?) 也就是说,很明显,我们在ClassA中没有Display1方法的定义,我们也不能使用ClassA实例访问同一个方法,因为它不是派生自任何像ClassB这样包含Display1方法的类。类ClassA不包含任何已定义的代码或变量。空类不会抛出任何错误,因为我们可以实例化一个看起来像(ClassA的实例)的对象。出现这个错误是因为类ClassA没有名为Display1的方法。但是类ClassB有一个名为Display1的方法。如果允许我们从ClassA本身访问classB的所有代码,那该有多有趣。 使用:运算符从ClassB派生类ClassA,代码如下: 隐藏,复制Code

ClassA:

  class ClassA:ClassB
    {
        
    }

ClassB:

class ClassB
    {
        public int x = 100;
        public void Display1()
        {
            Console.WriteLine("ClassB Display1");
        }
        public void Display2()
        {
            Console.WriteLine("ClassB Display2");
        }
    }

Program.cs 隐藏,复制Code

class Program
    {
        static void Main(string[] args)
        {
            ClassA a = new ClassA();
            a.Display1();
            Console.ReadKey();
        }
    }

现在按原样运行代码,我们得到一个输出。 输出 隐藏,复制Code

ClassB Display1

也就是说,现在ClassA可以访问ClassB继承的公共方法。错误消失,并调用ClassB中的Display1。如果在类的名称后面指定:,另一个类的名称,很多变化同时发生。a类现在据说是从b类派生出来的。这意味着我们在ClassB中编写的所有代码现在都可以在ClassA中访问和使用。如果我们真的写了所有包含在ClassA中的ClassB中的代码。如果我们创建了一个类似于ClassB的实例,它能做的一切,现在ClassA的实例也能做。但是我们还没有在ClassA中写一行代码。我们相信ClassA有一个变量x和两个函数Display1和Display2,因为ClassB包含这两个函数。因此,我们进入了继承的概念,其中ClassB是基类,ClassA是派生类。 让我们看另一种情况。假设我们遇到这样一种情况,ClassA也有一个与ClassB中的方法同名的方法。让我们也在ClassA中定义一个方法Derive1,这样我们的ClassA代码就变成: 隐藏,复制Code

class ClassA:ClassB
    {
        public void Display1()
        {
            System.Console.WriteLine("ClassA Display1");
        }
    }

ClassB:

class ClassB
    {
        public int x = 100;
        public void Display1()
        {
            Console.WriteLine("ClassB Display1");
        }
        public void Display2()
        {
            Console.WriteLine("ClassB Display2");
        }
    }

现在,如果我们运行应用程序使用以下代码片段为Program.cs类: 隐藏,复制Code

class Program
    {
        static void Main(string[] args)
        {
            ClassA a = new ClassA();
            a.Display1();
            Console.ReadKey();
        }
    }

问题是现在会发生什么?输出是什么?是否有任何输出或编译错误。好,我们来运行一下。 我们得到的输出: 隐藏,复制Code

ClassA Display1

但是你注意到一件事了吗,我们在运行代码时也收到了一个警告: 警告:' inheritanceandpolymorphism . class . display1()'隐藏了被继承的成员' inheritanceandpolymorphism . class . display1()'。如果需要隐藏,请使用new关键字。 请记住:没有人可以阻止派生类拥有在其基类中已经声明了相同名称的方法。 因此,ClassA无疑可以包含Display1方法,它在ClassB中已经用相同的名称定义了。 当我们调用a.Display1(), c#首先检查类ClassA是否有一个名为Display1的方法。如果没有找到,就检入基类。早期的Display1方法仅在基类ClassB中可用,因此被执行。这里,因为它在ClassA中,它从ClassA而不是ClassB中被调用。 请记住:派生类首先执行,然后是基类。 这样做的原因是基类可能有许多方法,由于各种原因,我们可能对它们的功能不满意。我们应该有完全的权利拥有要调用的方法的副本。换句话说,派生类方法覆盖基类中定义的方法。 如果我们在派生类中使用base关键字调用基类Display1方法会发生什么?,因此我们的ClassA代码为: 隐藏,复制Code

ClassA:

  class ClassA:ClassB
    {
        public void Display1()
        {
            Console.WriteLine("ClassA Display1");
            base.Display1();
        }
    }

ClassB:

class ClassB
    {
        public int x = 100;
        public void Display1()
        {
            Console.WriteLine("ClassB Display1");
        }
        public void Display2()
        {
            Console.WriteLine("ClassB Display2");
        }
    }

Program.cs 隐藏,复制Code

class Program
    {
        static void Main(string[] args)
        {
            ClassA a = new ClassA();
            a.Display1();
            Console.ReadKey();
        }
    }

输出 隐藏,复制Code

ClassA Display1 
ClassB Display1

我们在这里看到,ClassA Display1方法被调用,然后ClassB Display1方法被调用。 现在,如果您想要两个类中最好的,您可能想要先调用基类(ClassB) Display1,然后调用您的,反之亦然。为了实现这一点,c#提供了一个免费的关键字,称为base。关键字基可以在任何派生类中使用。它意味着从基类中调用该方法。因此基地。Display1将从类b调用方法Display1,也就是前面定义的类a的基类。 更多文章,请接触实际的方法。 注意:可以在派生类中使用一个名为“base”的保留关键字来调用基类方法。 如果我们用派生类ClassA的实例从基类调用Display2方法会怎样? 隐藏,收缩,复制Code

/// <summary>
/// ClassB: acting as base class
/// </summary>
class ClassB
 {
     public int x = 100;
     public void Display1()
     {
         Console.WriteLine("ClassB Display1");
     }
     public void Display2()
     {
         Console.WriteLine("ClassB Display2");
     }
 }

 /// <summary>
 /// ClassA: acting as derived class
 /// </summary>
 class ClassA : ClassB
 {
     public void Display1()
     {
         Console.WriteLine("ClassA Display1");
         base.Display2();
     }
 }

 /// <summary>
 /// Program: used to execute the method.
 /// Contains Main method.
 /// </summary>
 class Program
 {
     static void Main(string[] args)
     {
         ClassA a = new ClassA();
         a.Display1();
         Console.ReadKey();
     }
 }

输出 隐藏,复制Code

ClassA Display1
ClassB Display2

在上面的代码中,我们只做了一个很小的更改,base。Display1被base.Display2取代。在这个特定的场景中,调用类ClassB中的方法Display2。Base通常是一个非常通用的用途。它允许我们从派生类访问基类的成员,如前面解释的那样。我们不能在ClassB中使用base,因为根据我们的代码,ClassB不是派生自任何类。这样就完成了base关键字只能在派生类中使用? 让我们看另一个例子: 隐藏,收缩,复制Code

/// <summary>
/// ClassB: acting as base class
/// </summary>
class ClassB
 {
     public int x = 100;
     public void Display1()
     {
         Console.WriteLine("ClassB Display1");
     }
 }

 /// <summary>
 /// ClassA: acting as derived class
 /// </summary>
 class ClassA : ClassB
 {
     public void Display2()
     {
         Console.WriteLine("ClassA Display2");
     }
 }

 /// <summary>
 /// Program: used to execute the method.
 /// Contains Main method.
 /// </summary>
 class Program
 {
     static void Main(string[] args)
     {
         ClassB b = new ClassB();
         b.Display2();
         Console.ReadKey();
     }
 }

输出 错误:“InheritanceAndPolymorphism。ClassB'不包含'Display2'的定义,也没有扩展方法'Display2'接受类型'InheritanceAndPolymorphism的第一个参数。可以找到ClassB'(您是否丢失了using指令或汇编引用?) 请记住:继承不是向后工作的。 所以我们得到了一个错误。因为我们看到,ClassA是从ClassB派生出来的。, ClassB是基类。因此,类ClassA可以使用类ClassB的所有成员。继承没有向后兼容性,无论ClassA包含什么成员都不会向上渗透到ClassB。当我们试图从类ClassB的实例中访问类a的Display2方法时,它不能将其提供给类ClassB,从而出现错误。 注意:除了构造函数和析构函数外,类从基类继承了所有东西。 如果类ClassC从类ClassB派生,而类b又从类ClassA派生,那么类c将继承在类b和类a中声明的所有成员。这在继承中称为传递概念。派生类可以继承基类的所有成员,但不能从基类中删除成员。然而,派生类可以通过创建同名方法来隐藏基类的成员。基类的原始成员/方法不会被修改,也不受派生类中发生的任何事情的影响。它在基类中保持不变。,只是在派生类中不可见。 类成员可以是两种类型,即直接属于类的静态成员,或者通过类的实例访问且只属于该特定实例的实例成员。实例成员只能通过类的对象访问,不能直接由类访问。类中声明的默认成员是非静态的,我们只需通过使用static关键字使其为静态的。 所有类都派生自一个名为object的公共基类。所以Object是所有类的母体。 如果我们不从任何其他类派生任何类,则c#负责将:object本身添加到类定义中。对象是唯一不从任何其他类派生的类。它是所有类的最终基类。 假设类a是从类b派生的,就像在我们的例子中一样,但是类b不是从任何类派生的, 隐藏,复制Code

public class ClassB
 {
 }

 public class ClassA : ClassB
 {
 }

c#自动添加:object到ClassB,即,代码在编译时变为: 隐藏,复制Code

public class ClassB:object
{
}

public class ClassA : ClassB
{
}

但根据理论,我们说ClassB是ClassA的直接基类,所以ClassA的类是ClassB和object。 勒t的去另一个例子: 隐藏,复制Code

public class ClassW : System.ValueType
  {
  }

  public class ClassX : System.Enum
  {
  }

  public class ClassY : System.Delegate
  {
  }

  public class ClassZ : System.Array
  {
  }

我们有四个类定义,每个来自一个建于类在c#中,让我们运行代码。 我们得到很多编译时错误。 错误 隐藏,复制Code

'InheritanceAndPolymorphism.ClassW' cannot derive from special class 'System.ValueType'
'InheritanceAndPolymorphism.ClassX' cannot derive from special class 'System.Enum'
'InheritanceAndPolymorphism.ClassY' cannot derive from special class 'System.Delegate'
'InheritanceAndPolymorphism.ClassZ' cannot derive from special class 'System.Array'

不要害怕。 你注意到这个词的特殊类。定义我们的类不能继承特殊类在c#中建成的。 记住:在继承在c#中,定制类不能来自特殊的c#类像系统建成的。ValueType、系统。枚举系统。委托,系统。数组等。 一个例子, 隐藏,复制Code

public class ClassW
  {
  }

  public class ClassX
  {
  }

  public class ClassY : ClassW, ClassX
  {
  }

在上述例子中,我们看到三个类,ClassW, ClassX和优雅。优雅来自ClassW ClassX。现在如果我们运行代码,我们得到了什么? 编译时错误:InheritanceAndPolymorphism类”。优雅的InheritanceAndPolymorphism不能有多个基类:。ClassW’和‘ClassX”。 所以要记住一点:一个类只能来自一个类在c#中。c#不支持多重继承的类。 *多重继承在c#中可以通过使用接口来完成,我们不是本文讨论的接口。 我们不允许来自不止一个类,每个类只能有一个基类。 另一个例子: 假设我们试着写代码如下: 隐藏,复制Code

public class ClassW:ClassY
 {
 }

 public class ClassX:ClassW
 {
 }

 public class ClassY :  ClassX
 {
 }

代码非常可读的和简单的,ClassW来源于优雅,ClassX源自ClassW,优雅又来源于ClassX。所以没有多重继承的问题,我们的代码应该建立成功。让我们编译代码。我们得到了什么?又一个编译时错误。 错误:圆形基类涉及“InheritanceAndPolymorphism的依赖。ClassX’和‘InheritanceAndPolymorphism.ClassW”。 记住:是不允许循环依赖继承在c#中。ClassX来源于ClassW来源于优雅,优雅又来源于ClassX,造成循环依赖三个类,在逻辑上是不可能的。 均衡的实例/对象 让我们直接从一个真实的案例: 隐藏,复制Code

ClassB:
public class ClassB
    {
        public int b = 100;
    }

ClassA:

    public class ClassA
    {
        public int a = 100;
    }

Program.cs 隐藏,复制Code

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
    private static void Main(string[] args)
    {
        ClassB classB = new ClassB();
        ClassA classA = new ClassA();
        classA = classB;
        classB = classA;
    }
}

我们在这里试图将两个对象或两个不同的类的两个实例。让我们编译代码, 我们得到编译时错误: 错误 隐藏,复制Code

Cannot implicitly convert type 'InheritanceAndPolymorphism.ClassB' to 'InheritanceAndPolymorphism.ClassA'

Cannot implicitly convert type 'InheritanceAndPolymorphism.ClassA' to 'InheritanceAndPolymorphism.ClassB'

InheritanceAndPolymorphism是我用于控制台应用程序的名称空间,所以不需要害怕这个词,只是忽略它。 c#工作规则,它将永远不会让你把不同的相互独立的类的对象。因此,我们不能把一个对象classA classA classB classB反之亦然。不管类包含相似的结构和它们的变量初始化类似的整数值,即使我们做的。 隐藏,复制Code

public class ClassB
 {
     public int a = 100;
 }

 public class ClassA
 {
     public int a = 100;
 }

我只是改变了int b ClassB int。在这种情况下,将一个对象是不允许的,不可能的。 c#也非常特殊,如果它有处理的数据类型。 但是有一个方法。通过这种方式,我们将讨论其中的一个错误将会消失。唯一一次我们可以将不同的数据类型是只有当我们来自他们吗?看看下面提到的代码。中详细讨论这一点,当我们创建一个对象的ClassB宣布新的,我们创建两个对象,一个看起来像ClassB,另一个看起来像对象,即。来源于对象类(即最终基类)。所有类在c#中最终来源于对象。自ClassA来自ClassB我们宣布新的ClassA,我们创建三个对象,一个看起来像ClassB,一个看起来像ClassA和最后看起来像对象类。 隐藏,复制Code

public class ClassB
 {
     public int b = 100;
 }

 public class ClassA:ClassB
 {
     public int a = 100;
 }

 /// <summary>
 /// Program: used to execute the method.
 /// Contains Main method.
 /// </summary>
 public class Program
 {
     private static void Main(string[] args)
     {
         ClassB classB = new ClassB();
         ClassA classA = new ClassA();
         classA = classB;
         classB = classA;
     }
 }

我们只是ClassA来自ClassB,这是我们能做的,在本文中我们学到了很多关于这个。现在编译代码,我们得到: 错误:不能隐式类型转换的InheritanceAndPolymorphism。ClassB”到“InheritanceAndPolymorphism.ClassA”。存在一个显式转换(你失踪一吗?) 就像我提到的,c#非常讲究对象等同。 因此,当我们写classA = classB classA看起来像classA实例,classB对象和classB看起来像classB,在ClassB.Result有比赛吗?没有错误:-)。尽管classB和classA有相同的值,使用classB我们只能访问classB的成员,即使我们使用classA classA也可以访问。我们有贬值classB的效力。这个错误发生在classA = classB。类ClassA ClassB和更多。我们不能有右边的基类和派生类在左边。classB只代表一个classB而classA预计classA classA和classB。 要记住一点:,我们可以将一个对象的基类派生类而不是反之亦然。 另一个代码片段: 隐藏,复制Code

public class ClassB
    {
        public int b = 100;
    }

    public class ClassA:ClassB
    {
        public int a = 100;
    }

    /// <summary>
    /// Program: used to execute the method.
    /// Contains Main method.
    /// </summary>
    public class Program
    {
        private static void Main(string[] args)
        {
            ClassB classB = new ClassB();
            ClassA classA = new ClassA();
            classB=classA;
            classA = (ClassA)classB;
        }
    }

虽然我们违反了c#的情商在使用对象时,我们没有得到任何编译器错误,因为我们对对象进行了转换。()称为cast。在方括号中,类的名称是put。一个演员阵容基本上是一个伟大的平等。当我们打算写classA = classB时,c#期望等号的右边是一个classA,即。,一个ClassA实例。但是它找到了classB,即。,一个ClassB实例。当我们应用转换时,我们试着将ClassB的实例转换为ClassA的实例。这种方法满足c#关于只等同于相似对象类型的规则。记住,只有在这一行的持续时间里,classB才会变成ClassA而不是classB。 现在,如果我们将ClassB作为基类移除到class ClassA,就像下面的代码那样,并尝试将ClassA转换为ClassB对象。 隐藏,复制Code

public class ClassB
 {
     public int b = 100;
 }

 public class ClassA // Removed ClassB as base class
 {
     public int a = 100;
 }

 /// <summary>
 /// Program: used to execute the method.
 /// Contains Main method.
 /// </summary>
 public class Program
 {
     private static void Main(string[] args)
     {
         ClassB classB = new ClassB();
         ClassA classA = new ClassA();
         classB = (ClassB)classA;
         classA = (ClassA)classB;
     }
 }

输出 错误 隐藏,复制Code

Cannot convert type 'InheritanceAndPolymorphism.ClassA' to 'InheritanceAndPolymorphism.ClassB'
Cannot convert type 'InheritanceAndPolymorphism.ClassB' to 'InheritanceAndPolymorphism.ClassA'    

*'InheritanceAndPolymorphism ':我在我的应用中使用的命名空间,所以忽略它。 因此,我们看到,只有当这两个类中的一个是从另一个派生的时候,类型转换才有效。我们不能相互转换任何两个对象。 最后一个例子: 隐藏,复制Code

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
    private static void Main(string[] args)
    {
        int integerA = 10;
        char characterB = 'A';
        integerA = characterB;
        characterB = integerA;
    }
}

我们运行代码。 输出 错误:不能隐式地将类型'int'转换为'char'。存在显式转换(是否缺少强制转换?) 注意:我们不能隐式地将整型转换为char型,但是char型可以转换为int型。 结论 在本系列文章的这一部分中,我们学习了继承。为了深入理解这一概念,我们采用了各种场景和实际示例。在下一篇文章中,我们将讨论运行时多态。继承在运行时多态中扮演着非常重要的角色。 让我们列出所有需要记住的要点: 没有人可以阻止派生类拥有在其基类中已经声明了相同名称的方法。派生类第一次有机会执行,然后是基类。可以在派生类中使用一个名为“base”的保留关键字来调用基类方法。继承不会向后工作。除了构造函数和析构函数外,类从基类继承一切。在c#的继承中,自定义类不能从特殊的内建c#类派生,比如System。ValueType、系统。枚举系统。委托,系统。数组等。在c#中,类只能从一个类派生。c#不支持通过类的方式进行多重继承。循环依赖在c#继承中是不允许的。ClassX从ClassW派生而来,ClassW又从ClassY派生而来,ClassY又从ClassX派生而来,这导致了三个类之间的循环依赖,这在逻辑上是不可能的。我们可以将基类的对象等同于派生类,但反之则不行。我们不能隐式地将整型转换为char型,但是char型可以转换为int型。 在本系列的第一篇文章中,您可以阅读关于编译时多态性的内容。坚持编码和学习。 我的其他系列文章: MVC: http://www.codeproject.com/Articles/620195/Learning-MVC-Part-Introduction-to-MVC-Architectu RESTful webapi: http://www.codeproject.com/Articles/990492/RESTful-Day-sharp-Enterprise-Level-Application 编码快乐! 本文转载于:http://www.diyabc.com/frontweb/news2108.html

原文地址:https://www.cnblogs.com/Dincat/p/13457123.html