c#图解教程_第七章_类和继承

类继承


定义:使用已存在的类作为新类的基础

已存在的类称之为基类(base class) 新类称之为派生类(derived class)

派生类成员:

  • 本身声明的成员
  • 基类的成员

要声明一个派生类,需要在类名后面加入基类规格说明。基类规格说明由冒号和后面跟着用做基类的类名称组成,派生类被描述为直接继承自列出的基类

派生类扩展它的基类,因为他包含了基类的成员,加上在它本身声明中新增的功能

派生类不能删除它所继承的任务类成员

                           基类
                             ↓
Class class OtherClass : SomeClass{}

 

访问继承的成员


class SomeClass
{
    public string Field1="base class field ";
    public void Method1(string value)
    {
        Console.WriteLine("Base class -- Method1: {0}",value);
    }
}
class OtherClass:SomeClass
{
    public string Field2="derived class field";
    public void Method2(string value)
    {
        Console.WriteLine("Derived class -- Method2: {0}",value);
    }
}
class Program
{
    static void Main()
    {
        var oc=new OtherClass();
        oc.Method1(oc.Field1);  //以基类字段为参数的基类方法
        oc.Method1(oc.Field2);  //以派生字段为参数的基类方法
        oc.Method2(oc.Field1);  //以基类字段为参数的派生方法
        oc.Method2(oc.Field2);  //以派生字段为参数的派生方法
    }
}

 

所有类的派生自Object类


一个类声明的基类规格说明中只能由一个单独的类,称之为单继承

只允许直接继承一个类,但是继承的层次没有影响,可以不断叠加继承类的层次

class A{}

class B:A{}

class C:B{}

 

屏蔽基类的成员


虽然派生类不能删除它继承的任何成员,但可以用与基类同名的成员来屏蔽(mask)基类成员。这是继承的主要功能之一,非常实用。

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

 

使用new关键字屏蔽基类成员
,替代基类上的同名成员,调用该类使用新的方法字段或方法。

 

基类的访问


使用关键字Base

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()
    {
        var oc=new OtherClass();
        oc.PrintField1();
    //输出结果 →
      Field1 -- In the derived class
Field1 -- In the base class
} }

 

使用基类的引用

MyDerivedClass derived=new MyDerivedClass(); //实例化派生类
MyBaseClass mybc=(MyBaseClass)derived;  //显示转换为基类,转换引用

 

虚方法和覆写方法


class MyBaseClass
{
    virtual public void Print()  //关键字virtual,虚方法
    ...
}
class MyDerivedClass:MyBaseCLass
{
    override public void Print() //关键字Override,重写虚方法,覆写
    ...
}

覆写方法可以在继承的任何层次出现

当使用对象基类部分的引用调用一个覆写的方法时,方法的调用被沿派生层次上溯执行,一直到标记为override的方法的最高派生(most-derived)版本

如果在更高的派生级别有该方法的其他声明,但没有被标记为override,那么它们不会被调用

 

使用new 关键字调用方法 ,使用new方法的类调用的方法必是本身已被new的方法,而不是继承层次中最高层次的override的方法

class SecondDerived:MyDerivedClass
{
    new public void Print()
    {
        Console.WriteLine("This is the second derived class");
    }
}
class Program
{
    static void Main()
    {
        var derived=new SecondDerived();
        mybc=(MyBaseClass)derived;
        derived.Print();
        mybc.Print();  //输出结果 → This is the second derived class , This is the derived class
    }
}

 

 

 

 

 覆盖其他成员类型


派生类中具有同名字段,当将派生类转成基类时,基类调用的字段是派生类的字段值。

 

class MyBaseClass
{
    private int _myInt=5;
    virtual public int MyProperty
    {
        get{return _myInt;}
    }
}
class MyDerivedClass:MyBaseClass
{
    private int _myInt=10;
    override public int MyProperty
    {
        get{return _myInt;}
    }
}
class Program
{
    static void Main()
    {
        var derived=new MyDerivedClass();
        var mybc=(MyBaseClass)derived;
        Console.WriteLine(derived.MyProperty);  //输出结果:10
        Console.WriteLine(mybc.MyProperty);  //输出结果:10
    }
}

 

类访问修饰符


类的可访问性有两个级别:public和internal

  • 标记为public的类可以被系统内任何程序集中的代码访问
  • 标记为internal的类只能被它自己所在的程序集内的类看到

下图阐明了internal和public类从程序集外部的可访问性。类MyClass对左边程序集内的类不可见,因为MyClass被标记为internal。然而,类OtherClass对于左边的类可见,因为它是public。

 

 

程序间的继承


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

在不同程序集之间继承,需要满足两个条件:

  • 基类必须是public,这样才能从它所在的程序集外部访问它
  • 必须在Visual Studio工程中的References节点中添加包含对该基类的程序集的引用,可以在Solution Explorer中找到该标题

 

成员的访问修饰符


对类的可访问性,只有两种修饰符:internalPublic

 

 

 

 

抽象成员


抽象成员指设计为被覆写的函数成员。抽象成员有以下特征

  • 必须是一个函数成员,即字段和常量不能是抽象成员
  • 必须用abstract修饰
  • 不能有实现代码块。代码用分号表示
  • 共有4个类型的成员可以声明为抽象:方法、属性、事件、索引

例:抽象方法和抽象属性

abstract public void PrintStuff(string s);
abstract public int MyProperty
{
    get;
    set;
}

关于抽象成员的注意事项:

  • 尽管抽象成员必须在派生类中被覆写,但不能把virtual和abstract合用
  • 类似虚成员,派生类中抽象成员的实现必须指定override修饰符

 

抽象类


抽象类指设计为被继承的类。抽象类只能被用作其他类的基类。

  1. 不能创建抽象类的实例
  2. 抽象类使用abstract标识
  3. 抽象类可以包含抽象成员和普通的非抽象成员
  4. 抽象类可以派生自另一个抽象类。
  5. 任何派生自抽象类的类必须使用override关键字实现该类所有的抽象成员,除非派生类自己也是抽象类

抽象类和抽象方法示例

abstract class AbClass
{
    public void IdentifyBase()
    {
        Console.WriteLine("I am AbClass");
    }
    abstract public void IndetifyDerived();
}
class DerivedClass:AbClass
{
    override public void IdentifyDerived()
    {
        Console.WriteLine("I am DerivedClass";
    }
}
class Program
{
    static void Main()
    {
        // AbClass a=new AbClass(); ->抽象类不能够被实例化
        var b=new DerivedClass();
        b.IdentifyBase();         -> 输出结果:I am AbClass
        b.IdentifyDerived();      -> 输出结果 I  am DericedClass
    }
}

抽象类的另一个例子

例:包含数据成员和函类型成员的抽象类

abstract class MyBase
{
    public int SideLength=10;
    const int TriangleSideCount=3;
    abstract public void PrintStuff(string s);
    abstract public int MyInt{get;set;}
    public int PerimeterLength()
    {
        return TriangleSideCount*SideLength;
    }
}
class MyCLass:MyBase
{
    public override void PrintStuff(string s)
    {
        Console.WriteLine(s);
    }
    private int _myInt;
    public override int MyInt
    {
        get{return _myINt;}
        set{_myInt=value;}
    }
}
class Program
{
    static void Main()
    {
        var mc=new MyClass();
        mc.PrintStuff("This is a string.");
        mc.MyInt=28;
        Console.WriteLine(mc.MyInt);
        Console.WriteLine("Perimeter Length:{0}",mc.PerimeterLength());
    }
}

密封类


抽象类必须用作基类,它不能被实例化。
密封类与抽象类相反。

  • 密封类只能被用作独立的类,不能用作基类(被继承)
  • 密封类使用sealed修饰符标注
sealed class Myclass{}

 

静态类


静态类中所有成员都是静态的。静态类用于存放不受实例数据影响的数据和函数。静态类常见用途就是创建一个包含一组数学方法和值的数学库。

  • 静态类本身必须标记为static
  • 类的所有成员必须是静态的
  • 类可以用一个静态构造函数,但不能有实例构造函数,不能创建该类的实例
  • 静态类是隐式密封的,即不能继承静态类
sealed class MyClass{}

静态类

static public class MyMath
{
    public static float PI=3.14f;
    public static bool IsOdd(intx)
    {
        return x%2==1;
    }
    public static int Times2(int x)
    {
        return 2*x;
    }
}
class Program
{
    static void Main()
    {
        int val=3;
        Console.WriteLine("{0} is odd is {1}",val,MyMath.IsOdd(val));  ->类名.静态成员
        Console.WriteLine("{0} * 2 = {1}",val,MyMath.Time2(val));
    }
}

扩展方法


扩展方法允许编写的方法和声明它的类之外的类关联。
扩展方法的重要要求如下:

  • 声明扩展方法的类必须声明为static
  • 扩展方法本身必须声明为static
  • 扩展方法必须包含关键字this作为它的第一个参数类型,并在后面跟着它所扩展的类的名称

例:扩展方法示例

namespace ExtensionMethods
{
    sealed class MyData
    {
        private double D1,D2,D3;
        public MyData(double d1,double d2,double d3)
        {
            D1=d1;D2=d2;D3=d3;
        }
        public double Sum()
        {
            return D1+D2+D3;
        }
    }
    static class ExtendMyData
    {
        public static double Average(this MyData md)
        {
            return md.Sum()/3;
        }
    }
    class Program
    {
        static void Main()
        {
            var md=new MyData(3,4,5);
            Console.WriteLine("Sum: {0}",md.Sum());
            Console.WriteLine("Average: {0}",md.Average());
        }
    }
}

 

 命名约定


 

 

 

posted @ 2021-07-16 18:07  suspect!  阅读(129)  评论(0)    收藏  举报
//增加一段JS脚本,为目录生成使用