类的继承与派生(virtual、override)

C#中类的继承与派生在性质上类似C++,但在有些方面有一些区别。

C#中所有类都派生自object类

除了特殊的类object,所有的类都是派生类,即使他们没有基类规格说明,类object是唯一的非派生类,因为他是继承层次结构的基础,与C++不同(C++中允许多继承),在C#中一个类声明的基类规格说明中只能有一个单独的类,也就是只允许单继承,虽然类只能直接继承一个基类,但继承的层次没有限制。在写法上也与C++不同,C#中不存在公有继承、私有继承等这些继承方式,所以在写的时候冒号后面直接接上基类的名字即可,例如 class A : B

屏蔽基类成员

虽然子类不能删除它继承的任何成员,但可以用与父类成员名称相同的成员来屏蔽(mask)父类成员,这是继承的主要功能之一。

屏蔽的使用:
(1)屏蔽一个继承的数据成员,需要声明一个新的相同类型的成员,并使用相同名称
(2)屏蔽一个继承的函数成员,需要声明一个带有相同签名的函数成员,签名由名称和参数列表组成,不包括返回类型
(3)要让编译器知道你在故意屏蔽继承的成员,可以使用new修饰符,否则,程序可以成功编译,但编译器会警告你隐藏了一个继承的成员
(4)也可以屏蔽静态成员

    class A
    {
        public int i;
        public void foo(){ }
    }

    class B :A 
    {
        new public int i;
        public void foo() { }  //不加new会有一个警告

    }

基类访问

表达式:base.成员

虚方法(virtual)和覆写方法(override)

类似C++中的多态的产生,C++中使用子类对象给父类指针赋值,当该父类指针调用虚函数时,就会产生多态,同理C#中使用子类对象的栈上引用给父类引用赋值,当父类引用调用虚方法时,就会产生多态。

    class A
    {
        public virtual void foo()
        {
            Console.WriteLine("父类");
        }
    }

    class B :A 
    {
        public override void foo()
        {
            Console.WriteLine("子类");
        }  
    }

    class Program
    {
        static void Main(string[] args)
        {
            B b = new B();
            A a = (A)b;
            a.foo();  //输出子类
        }
    }

virtual和override修饰符的使用

父类中被覆写的方法用virtual来修饰,子类中覆写后的方法需要用override来修饰

(1)覆写和被覆写的方法必须有相同的可访问性
(2)不能覆写static方法或非虚方法
(3)方法、属性、索引器以及事件,都可以被声明为virtual和override

virtual与override的内部调用机制

当使用对象基类部分的引用调用一个覆写的方法时,方法的调用被沿派生层次上溯执行,取寻找标记为override的方法,如果在更高的派生级别有该方法的其他声明,但没有被标记为override,那么它们不会被调用

  class A
    {
        public virtual void foo()
        {
            Console.WriteLine("A");
        }
    }

    class B :A 
    {
        public override void foo()
        {
            Console.WriteLine("B");
        }  
    }

    class C:B
    {
        public override void foo()
        {
            Console.WriteLine("C");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            C c = new C();
            A a = (A)c;
            a.foo();    //输出C
        }
    }

此时a调用foo函数,会根据继承关系向上寻找override方法,在C中有此方法则会调用到C中的foo所以打印出C

    class C:B
    {
        public new void foo()
        {
            Console.WriteLine("C");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            C c = new C();
            A a = (A)c;
            a.foo();    //输出B
        }
    }

如果将C中的foo函数使用new来修饰,而不是override,则在调用时找不到C中的override修饰的foo函数,则只能调用B中被override修饰的foo函数所以输出为B

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值