前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >c#之继承

c#之继承

作者头像
liulun
发布2022-05-09 10:55:43
2960
发布2022-05-09 10:55:43
举报
文章被收录于专栏:liulun

一:继承的分类 从c#中的继承可以分为两种(其他面向对象的语言貌似也是这样) 实现继承(不能实现多重继承,子类只能从一个父类派生) 接口继承(可以从多个接口派生) 结构是值类型的,不支持实现继承,支持接口继承,可以派生于多个接口 二:修饰符

public

任何代码均可访问

protected

仅派生类型可访问,实例对象不可访问

internal

程序集内部可访问

private

只能在类内部访问

protected internal

程序集内部派生类中

new

用相同的签名覆盖基类中的成员

static

成员不在类的具体实例上执行

virtual

成员可以由派生类重写

abstract

只定义成员的签名,没有实现代码

override

该成员重写了基类中的相同签名的virtual成员,并允许被再次重写

sealed

该成员重写了基类中的相同签名的virtual成员,并不允许被再次重写

三: 子类拥有父类的所有子类可见成员 这也是设计子类的目的之一,为了扩展父类的功能

四:重写 方法只要声明为virtual,就可以被子类中签名相同的方法重写(override) 当然子类也可以不重写这个方法 成员字段和静态函数都不能被声明为virtual 一个方法被修饰成override,这个方法仍旧可以被它的子类重写

五:覆盖 用new关键字可以隐藏基类的方法,字段 这个感觉没什么好说的 综合例子一(看输出结果之前,希望你能仔细想以想)

代码语言:javascript
复制
    public class baseClass
    {
        public void Methord()
        {
            Console.WriteLine("methord from base");
        }
        public virtual void Methord2()
        {
            Console.WriteLine("virtual methord from base");
        }
    }
    public class sonClass : baseClass
    {
        public new void Methord()
        {
            Console.WriteLine("methord form son");
        }
        public override void Methord2()
        {
            Console.WriteLine("override methord from son");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            baseClass b = new baseClass();
            b.Methord();
            b.Methord2();
            Console.WriteLine();

            sonClass s = new sonClass();
            s.Methord();
            s.Methord2();
            Console.WriteLine();

            baseClass b2 = new sonClass();
            b2.Methord();
            b2.Methord2();
            Console.WriteLine();

            sonClass s2 = (sonClass)b2;
            s2.Methord();
            s2.Methord2();
            Console.WriteLine();
            
            Console.ReadKey();
        }
    }

输出结果为:

image
image

很多面试题中都有类似的题 我做个总结 一般情况下变量的类型是什么,该变量就拥有什么类型的成员 即使像下面这种情况也不例外 baseClass b2 = new sonClass(); b2的成员是baseClass中的成员 b2与sonClass中的成员无关 只有一种情况除外 当父类中的virtual方法已经被子类中的方法override过之后(new重写过之后是不行的) 类似这种情况baseClass b2 = new sonClass(); b2拥有的是重写过的方法成员 具体的原理以后有机会分析一下IL代码 那么我们总结一下这个现象 每个类型都有自己的类型成员表,虚方法成员是动态绑定的,运行时动态覆盖

综合例子二

代码语言:javascript
复制
    public class A
    {
        public virtual void Fun1(int i)
        {
            Console.WriteLine(i);
        }

        public void Fun2(A a)
        {
            a.Fun1(1);
            Fun1(5);
        }
    }
    public class B : A
    {
        public override void Fun1(int i)
        {
            base.Fun1(i + 1);
        }

        public static void Main()
        {
            B b = new B();
            A a = new A();
            a.Fun2(b);
            b.Fun2(a);
            Console.ReadKey();
        }
    }

输出为

image
image

就不多解释了

六:通过base关键字获取基类的成员 看个比较特殊的例子

代码语言:javascript
复制
    public class baseClass
    {
        public virtual void Methord2()
        {
            Console.WriteLine("virtual methord from base");
        }
    }
    public class sonClass : baseClass
    {
        public override void Methord2()
        {
            base.Methord2();
            Console.WriteLine("override methord from son");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            baseClass b2 = new sonClass();
            b2.Methord2();
            
            Console.ReadKey();
        }
    }

输出为:

image
image

由此可见重写方法是可以通过base关键字调用被重写的方法的 基类的成员表在重写方法中是可见的

七:抽象类和抽象方法(abstract) 抽象类不能实例化 抽象方法没有执行代码 如果类包含抽象方法,那么该类也必须声明为abstract 当然一个声明为abstract的类可以包含实例方法 抽象方法与虚方法类似,也是运行时动态绑定的 八:密封类和密封方法(sealed) 密封类不能被继承 sealed关键字只能修饰重写(override)方法 密封方法不能被重写 但是可以通过new关键字覆盖它 除非特殊情况最好少用这个关键字

九:继承关系中的构造函数 初始化一个类的实例的具体步骤是 1:初始化该类的字段 2:初始化基类的字段 3:初始化基类的构造函数 4:初始化该类的构造函数 可以通过base关键字制定初始化基类中的哪个构造函数 再看个综合例子,你觉得应该输出什么

代码语言:javascript
复制
    class A 
    { 
          public A() 
          { 
                PrintFields(); 
          } 
          public virtual void PrintFields(){} 
      }
    class B : A
    {
        int x = 1;
        int y;
        public B()
        {
            y = -1;
            PrintFields();
        }
        public override void PrintFields()
        {
            Console.WriteLine("x={0},y={1}", x, y);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            A b = new B();
            Console.ReadKey();
        }
    }

输出为:

image
image

就不多解释了

十:接口继承 接口继承和实现继承其实差不多 做几点说明: 1.一个类可以实现多个接口 2.不允许提供接口中任何成员的实现方式 3.接口只能包含方法,属性,所引器和事件,不允许包含运算符重载 4.不能实例化接口,因此接口不能有构造函数 5.不能声明成员修饰符,接口成员总是公共的,也不能声明成员为虚拟的或者静态的,这些是具体实现的时候做的事情

做此文得到了郑州的Xuefly的支持,在此表示感谢

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2009-05-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档