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中找到该标题
成员的访问修饰符
对类的可访问性,只有两种修饰符:internal和Public


抽象成员
抽象成员指设计为被覆写的函数成员。抽象成员有以下特征
- 必须是一个函数成员,即字段和常量不能是抽象成员
- 必须用abstract修饰
- 不能有实现代码块。代码用分号表示
- 共有4个类型的成员可以声明为抽象:方法、属性、事件、索引
例:抽象方法和抽象属性
abstract public void PrintStuff(string s); abstract public int MyProperty { get; set; }
关于抽象成员的注意事项:
- 尽管抽象成员必须在派生类中被覆写,但不能把virtual和abstract合用
- 类似虚成员,派生类中抽象成员的实现必须指定override修饰符

抽象类
抽象类指设计为被继承的类。抽象类只能被用作其他类的基类。
- 不能创建抽象类的实例
- 抽象类使用abstract标识
- 抽象类可以包含抽象成员和普通的非抽象成员。
- 抽象类可以派生自另一个抽象类。
- 任何派生自抽象类的类必须使用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()); } } }


命名约定


浙公网安备 33010602011771号