(五)CSharp-继承

一、继承概念

继承类型分为两种: 实现继承和接口继承。

多重继承: 一个类派生自多个类。

C# 不支持多重实现继承,但允许多重接口继承。

结构不支持继承: 结构不支持实现继承,但是可以支持接口继承

  • 结构总是派生自 System.ValueType,它们还可以派生自任意多个接口。
  • 类总是派生自 System.Object 或用户选择的另一个类,它们还可以派生自任意多个接口。

二、对基类的访问和引用

基类访问

   class SomeClass
    {
        public string Field1 = "Field1 -- In the base class";
    }

    class OtherClass : SomeClass
    {
        new public string Field1 = "Field1 -- In the derived class";

        public void PrintField1()
        {
            Console.WriteLine(Field1); // 访问派生类
            Console.WriteLine(base.Field1); //访问基类
        }

    }

    class Program
    {
        static void Main(string[] args)
        {
            OtherClass oc = new OtherClass();
            oc.PrintField1();
           Console.ReadKey();
        }
    }

使用基类的引用


    class MyBaseClass
    {
        public void Print()
        {
            Console.WriteLine("This is the base class.");
        }
    }

    class MyDerivedClass : MyBaseClass
    {
        public int var1;
        new public void Print()
        {
            Console.WriteLine("This is the derived class.");
        }
    }


class Program
    {
        static void Main(string[] args)
        {
            MyDerivedClass derived = new MyDerivedClass();
            MyBaseClass mybc = (MyBaseClass)derived;

            derived.Print();
            mybc.Print();

            Console.ReadKey();
        }
    }

输出结果:

Field1 – In the derived class
Field1 – In the base class

三、虚方法

1、声明定义虚方法

把一个基类函数声明为 virtual,就可以在任何派生类中重写该函数。

    class MyBaseClass
    {
        //虚方法
        public virtual string VirualMethod()
        {
            return "This method is virtual and defined in MyBaseClass";
        }

        //虚属性
        public virtual string ForeName
        {
            get { return foreName; }
            set { foreName = value; }
        }

        private string foreName;
        
    }

    class MyDerivedClass : MyBaseClass
    {
        //使用 override 来 重写虚方法
        public override string VirualMethod()
        {
            return "This method is an override define in MyDerivedClass";
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            MyDerivedClass derived = new MyDerivedClass();
            MyBaseClass mybc = (MyBaseClass)derived;

            Console.WriteLine(derived.VirualMethod());
            Console.WriteLine(mybc.VirualMethod());

            Console.ReadKey();
        }
    }

输出结果:

This method is an override define in MyDerivedClass
This method is an override define in MyDerivedClass

从结果可知,派生类转换为基类,其结果仍是调用派生类重写的虚方法。

2、调用函数的基类版本

若派生类在基类的基础上,对虚方法进行代码逻辑的补充时:

    class CustomerAccount
    {
        public virtual decimal CalculatePrice()
        {
            return 0.0M;
        }

        class GoldAccount : CustomerAccount
        {
            public override decimal CalculatePrice()
            {
                return base.CalculatePrice() * 90;
            }
        }
    }
    

3、虚方法小结:

  • 在 C# 中,函数在默认情况下不是虚拟的,但(除了构造函数以外)可以显式地声明为 virtual。
  • C# 要求在派生类的函数重写另一个函数,要使用 overiride 关键字显式声明。
  • 成员字段和静态函数都不能声明为 virual。
  • 虚方法不可用 private 修饰符

四、隐藏方法

如果在基类和派生类中,有签名相同的方法,但该方法没有分别声明为 virrual 和 override,派生类方法就会隐藏基类方法。

隐藏方法存在安全隐患: 由于派生类和基类使用的是相同签名的方法,但该方法执行的结果不相同。若程序员想要调用派生类的,但不小心调用的是基类的,该方法执行后会出现潜在程序的错误。

五、抽象类与抽象函数

  • C# 允许把类和函数声明为 abstract。
  • 抽象类不能实例化,抽象函数不能直接实现,必须在非抽象的派生类中重写。
  • 抽象函数本身也是虚拟的
  • 如果类包含抽象函数,则该类也是抽象的,也必须声明为抽象的。
abstract class Building
{
public abstract decimal CalculateHeatingCost();// abstract method
}

六、密封类和密封方法

C# 允许把类和方法声明为 sealead。对于类,这表示不能继承该类;对于方法(属性也可密封),这表示不能重写该方法。(密封方法,是否可以使得隐藏方法更加安全)

1、密封类:

 sealed class FinalClass
    {

    }
    
//提示错误,密封类不能被继承
    class DerivedClass : FinalClass
    {

    }

2、密封方法

  class MyBaseClass1
    {
        public virtual void TestFun()
        {

        }
    }

        class FinalClass : MyBaseClass1
    {
        sealed public override void TestFun()
        {

        }
    }

    class DerivedClass : FinalClass
    {
        //提示错误,密封方法不能被重写
        //因为继承的这个基类设置该方法为密封方法
        public override void TestFun()
        {

        }
    }

七、可见性修饰符

表-修饰符的访问说明

修饰符 应用于 说明
public 所有类或成员 任何代码均可以访问该项
protected 类型和内联类型的所有成员 只有派生的类型能访问该项
internal 所有类型或成员 只能在包含它的程序集中访问该项
private 类型和内联类型的所有成员 只能在它所属的类型中访问该项
protected internal 类型和内联类型的所有成员 只能在包含它的程序集和派生类型的任何代码中访问该项

内嵌类型: 在类的内部再声明一个类

    public class OtherClass
    {
        private int id = 0;
        protected class InnerClass
        {
            public void InnerClassFun()
            {
                OtherClass oc = new OtherClass();
                oc.id = 0;//可访问
            }
        }
    }

表-成员可访问性总结(出自《C# 图解教程》-8.9.7 成员访问修饰符小结)

同一程序集内的类 同一程序集内的类 不同一程序集内的类 不同一程序集内的类
非派生类 派生类 非派生类 派生类
private
internal
protected
protected internal
public

其他修饰符

修饰符 应用于 说明
new 函数成员 成员用相同的签名隐藏继承的成员
staitc 所有成员 成员不作用于类的具体实例
virtual 仅函数成员 成员可以由派生类重写
abstract 仅函数成员 虚拟成员定义了成员的签名,但没有提供实现代码
override 仅函数成员 成员重写了继承的虚拟或抽象成员
sealed 类、方法和属性 对于类,不能继承自密封类。对于属性和方法,成员重写已继承的虚拟成员,但任何派生类中的任何成员都不能重写该成员。该修饰符必须与 override 一起使用
extern 仅静态(DllImport)方法 成员在外部用另一种语言实现

八、程序集间的继承

C# 允许从一个在不同的程序集内定义的基类来派生类。

要从不同程序集中定义的基类派生类,必须具备以下条件:

  • 基类必须被声明为 public,这样才能从它所在的程序集外部访问它。
  • 必须在 Viusal Studio 工程中的 Reference 节点中添加包含该基类的程序集的引用。

你可能感兴趣的:(CSharp,c#)