zoukankan      html  css  js  c++  java
  • 多态和继承(继承)

    多态和继承(继承)

    本文是深入浅出OOP第二篇,主要说说继承的话题。

    继承的介绍

    在OOP中,继承有如下的定义:

    • 继承是一种OOP的机制,用于派生继承预定义的类
    • 在这个继承关系中,预定义的类是基类,新类是子类
    • 继承常常用于实现代码重用
    • 继承允许子类复用基类非private的的数据和方法

    继承的实现

    创建一个Console工程,命名为InheritanceAndPolymorphism。添加ClassA、ClassB类,并拷贝下面的代码:

    复制代码
    ClassA:
    
       class ClassA
         {
            
         }
    
    ClassB:
    
        class ClassB
        {
            public int x = 100;
            public void Display1()
            {
                Console.WriteLine("ClassB Display1");
            }
            public void Display2()
            {
                Console.WriteLine("ClassB Display2");
            }
        }
    复制代码

    Program.cs中,调用ClassA

    复制代码
    class Program
        {
            static void Main(string[] args)
            {
    
                ClassA a = new ClassA();
                a.Display1();
            }
        }
    复制代码

    如果运行,肯定会报错的。

    Error'InheritanceAndPolymorphism.ClassA' does not contain a definition for 'Display1' and no extension method 'Display1' accepting a first argument of type 'InheritanceAndPolymorphism.ClassA' could be found

    因为我们在ClassA中未定义Display1的方法。 下面我们重写,使ClassA继承自ClassB。

    复制代码
    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");
            }
        }
    复制代码

    再次运行,结果如下:

    ClassB Display1

    ClassA已经可以访问其基类的Display1函数了,这个简单的实例说明了继承可复用基类的妙处,下面这张图以父子财产继承关系说明了继承的意义

    image

    再来看另外一个场景,假设ClassA也有一个Display1函数,签名和其基类一样的:

    复制代码
    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");
            }
        }
    复制代码

    执行后结果如下:

    ClassA Display1

    看起来结果是对的,ClassA默认调用了自己的Display1函数,但是Visual Studio有一个警告:

    Warning: 'InheritanceAndPolymorphism.ClassA.Display1()' hides inherited member 'InheritanceAndPolymorphism.ClassB.Display1()'. Use the new keyword if hiding was intended.

    C#中对方法的调用首先是查询ClassA自己中有无Display1函数,再查询其基类有无Display1函数。在基类和子类出现同样函数的情况现实项目中是存在的,可能是基类代码过于陈旧了,子类既想用同签名的函数,又无法停止基类的同签名函数,故会出现这样的警告---尽管逻辑正确,但是这种设计还是有一些瑕疵的。

    我们再试试在CalssA中通过base调用基类同名方法的情况:

    复制代码
    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");
            }
        }
    复制代码

    执行结果如下:

    ClassA Display1

    ClassB Display1

    这个实验说明C#提供了base关键词,用于在继承中子类调用基类的函数或者变量(非private类型)。

    image

    同样的,在ClassA.Display1中调用其基类的Display2也是可以的,代码如下所示:

    复制代码
    /// <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();
            }
        }
    复制代码

    执行结果如下:

    ClassA Display1

    ClassB Display2

    那么可否通过基类调用其子类的函数呢?

    复制代码
    /// <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();
            }
        }
    复制代码

    运行报错:

    Error: 'InheritanceAndPolymorphism.ClassB' does not contain a definition for 'Display2' and no extension method 'Display2' accepting a first argument of type 'InheritanceAndPolymorphism.ClassB' could be found

    原因是继承无法实现逆向调用,既基类无法调用子类。

    除了构造函数和析构函数,子类继承了其基类的一些(包括private的成员变量和成员函数,只是无法访问)。

    在C#中,一个类默认继承的是object类型,object是C#所有引用类型的基类;同时,继承具有传递性,如ClassC继承自ClassB,ClassB继承自ClassA,则ClassC可完全复用ClassA的数据和函数---ClassC继承了ClassA。

    C#中所有的类型都可被继承吗?

    复制代码
    public class ClassW : System.ValueType
       {
       }
    
       public class ClassX : System.Enum
       {
       }
    
       public class ClassY : System.Delegate
       {
       }
    
       public class ClassZ : System.Array
       {
       }
    复制代码

    执行结果:

    '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'

    运行的结果让人抓狂

    image

    在C#中,自定义类无法继承自C#内置的一些类,如System.ValueTypeSystem.EnumSystem.DelegateSystem.Array, etc。

    下面这个例子我们再看看C++中的多类继承是否可在C#中实现:

    复制代码
        public class ClassW
        {
        }
    
        public class ClassX
        {
        }
    
        public class ClassY : ClassW, ClassX
        {
        }
    复制代码

    执行结果:

    Compile time Error: Class 'InheritanceAndPolymorphism.ClassY' cannot have multiple base classes: 'InheritanceAndPolymorphism.ClassW' and 'ClassX'.

    执行结论是:C#仅支持单类继承,不支持C++的这种星型继承关系。 要使用星型继承关系,请用接口实现。

    那么可否实现循环依赖继承呢?

    复制代码
       public class ClassW: ClassY
        {
        }
    
        public class ClassX: ClassW
        {
        }
    
        public class ClassY :  ClassX
        {
        }
    复制代码

    代码逻辑很简单,ClassW继承自ClassY,ClassX继承自ClassW, ClassY继承自ClassX。

    但是编译后报错了:

    Error: Circular base class dependency involving 'InheritanceAndPolymorphism.ClassX' and 'InheritanceAndPolymorphism.ClassW'.

    image

    我们得出一个结论,C#中不许环形依赖继承。

    实例对象的是否可赋值

    复制代码
    ClassB:
    public class ClassB
        {
            public int b = 100;
        }
    
    ClassA:
    
        public class ClassA
        {
            public int a = 100;
        }
    复制代码

    Program.cs 代码如下

    复制代码
    /// <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的对象是否可赋值。

    编译的结果是:报错了

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

    image

    尽管ClassA和ClassB里面的数据成员变量a数据一致,都为100,但是这里用等号比较的是类型--引用地址,故无法进行赋值。

    我们再来试试继承关系的:

    复制代码
    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,我们希望可以直接赋值其实例对象。

    运行结果如下:

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

    运行结论:C#中子类对象可直接赋值给基类对象,基类对象需要往下强转。代码修改如下:

    复制代码
    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;
            }
        }
    复制代码

    这样编译就通过了。

    如果ClassA不继承自ClassB,则这种强转在C#中是会报错的:

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

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

     

    本节结论

    • 无法阻止子类覆盖基类同签名方法
    • 继承关系是子类的同签名方法先查找,再查找其基类的
    • base关键字被C#用于在子类中调用基类函数、变量
    • 继承关系不可逆转
    • 除了构造函数、析构函数,子类继承了基类的一些
    • 自定义类默认继承自Object类型,但是C#的这些类型不能被继承:System.ValueTypeSystem.EnumSystem.DelegateSystem.Array, etc.
    • C#不支持从多类继承
    • C#不支持循环继承
    • 子类对象可直接赋值给基类,反之需要强转

    原文地址:Diving in OOP (Day 2): Polymorphism and Inheritance (Inheritance)

  • 相关阅读:
    java_doc
    zai~~myGODDDD
    get span time
    someThing about thread
    互斥
    http://www.vchelp.net/services/about_us/itbookreview_intro.asp
    (十三)sealed、new、virtual、abstract 和 override java程序员
    (15) 常用基础知识 java程序员
    (14)abstract class 和 interface java程序员
    (16) 结构和类 java程序员
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4426027.html
Copyright © 2011-2022 走看看