C#面向对象的程序设计提升

静态成员与静态类

  • “类”一般不包含数据信息,真正的数据信息属于类的特定实例(对象)。但是有一些数据信息需要属于类而不属于对象(如用一个变量来确定一个类一共有多少个对象),把这些属于类而不属于对象的成员定义为***静态成员***。

类的静态成员

  • 静态成员和非静态成员的区别:1.静态成员属于类而不属于对象,只能通过类来访问;非静态成员属于类的实例;
  • 标识:静态成员通过static关键字来标识。可以是静态方法、静态字段、静态属性等。
使用静态成员时要注意
  • 静态成员属于类,只能通过类名引用;因此C#表示当前实例的关键字this不能在静态方法中使用
  • 静态数据成员在所有对象之外单独开辟内存空间。即使没有类的实例化操作,系统也会为静态成员分配内存空间,因此容许随时引用。
  • 非静态方法也叫实例方法。在实例方法中,可以直接访问静态成员和静态方法;但在静态方法中,只能访问静态成员,不可以直接访问实例成员或实例方法;

静态构造函数

  • 静态构造函数用来初始化类的静态字段。其与实例构造函数共存。其并不对类的特定实例进行操作,所以也称为全局构造函数或共享构造函数。
  • 在类的第一个实例创建之前或者调用类的任何静态方法之前,系统会自动执行静态构造函数,最多执行一次。在C#中,不能直接调用静态构造函数。
  • 声明静态构造函数:
static 静态构造函数名()//与类名相同
{}//不能带访问修饰符,不能有任何参数列表和返回值
//不支持重载,就是说只能有一个;

静态类

  • 静态类:当类只包括静态成员时,可以用static把它声明为静态类。
  • 静态类的特点:1.仅包含静态成员;2.不能被实例化;3.是密封的;因此不能被继承。4.不能包含实例构造函数;
  • 静态类优点:1.编译器会自动执行检查,以确保不添加实例成员;2.由于不必创建对象就能调用其方法,所以静态类更简单迅速。
  • 在.NET Framework中,存在大量的静态类(如Console、Math);

类的继承性

  • 类的继承性为面向对象程序设计构造一个分层类结构体系创造了条件。如:.NET Framework类库就是一个分层类结构体系。其中,Object类是一个最上层的基类,其他所有类都是直接或间接由Object类派生而来的,即使用户自定义的类没有指定继承关系,系统仍然将该类作为Object类的派生类。
  • C#中类的继承遵循原则:1.单一继承。派生类只能从一个类中继承;2.派生类不能继承基类的构造函数;3.类的继承是可以传递的;

C#中派生类的声明:

[访问修饰符] class 类名 : 基类名
{
//类的成员
}

构造函数

  • 派生类的构造函数:(派生类不能继承基类的构造函数)派生类的构造函数只初始化新添加的成员字段;在创建派生类对象时,系统会先调用基类的构造函数,完成基类部分的成员初始化,再调用派生类的构造函数完成派生类的新添加的成员初始化。
默认构造函数
  • 在创建派生类的实例时,系统将自动调用不带参数的默认构造函数;先调用基类的默认构造函数,再调用派生类的默认构造函数;
  • 构造函数可重载;
带参数的构造函数
  • 在创建派生类的实例的时候,调用的是基类的默认构造函数,当我们需要调用基类的带参数的构造函数时,就可以在声明派生类的构造函数时,加base关键字向基类构造函数传递参数。
class Father//基类
{
protected string name;
public Father(string name)//基类构造函数
{
this.name=name;
}
}
class Son:Father //派生类
{
int age;
public Son(string name,int age):base(name)//派生类构造函数,调用了基类带参数的构造函数,base(name)=Fateher(name)
{
this.age=0;
}}
  • 当基类没有默认构造函数而只有带参数的构造函数时,在声明派生类默认构造函数时,也是用base关键字;
public Dog():base("未知“,0//派生类的默认构造函数
{
type="未知"
}

密封类

  • 将类密封,阻止继承;
  • 在C#中,使用关键字sealed声明密封类:
public sealed class Animal
{
}

类的多态性

  • 类的多态性:派生类对基类的特征和行为的改变,表面上看这些特征或行为还是相似的。(当派生类从基类继承时,派生类不仅不仅会获得基类的所有字段、属性和方法等成员,还会扩展基类的成员/重写基类的成员,以更改基类的数据和行为)
  • C#类的多态性的方法:1.(替换)使用新的派生类成员替换基类成员;2.(覆盖)重写虚拟的基类成员;
  • new替换和override覆盖的区别:首先替换直接就像换器官一样,基类的需要替换的成员将废除。时间不同,C#中替换发生在程序编译之前,而覆盖发生在程序运行之时;

new替换:使用new重新定义类的成员

  • new替换:使用new关键字来定义与基类中同名的成员,即可替换基类的成员。
  • 格式:把new关键字放置要替换的类成员的数据类型之前;
public new string Eat()//在派生类中重新定义基类中的方法
{
return string.Format("狗狗({0}):我是二狗!",name);
}

override覆盖:重写虚拟的基类成员

  • virtual-override:在基类中首先用virtual关键字声明这个成员为虚拟成员,然后在派生类中用override关键字重载虚拟成员或覆盖虚拟成员;
  • 注意:1.字段不能虚拟;只有方法、属性、事件、索引器才可虚拟;2.派生类可通过密封来停止虚拟继承,此时派生类的成员使用sealed override声明;
虚方法及重载
  • 直接上例子:(基类与派生类中的”方法名称与参数列表"必须完全一致)
public class Animal//基类
{
public virtual string Eat()//将此方法虚拟
{
return string.Format("动物{0}:我要吃东西!",name);
}
}

public class Dog:Animal//派生类
{
public override string Eat()//覆盖基类的虚方法
{
return string.Format("狗狗{0}:我要吃骨头!",name);
}
}
虚方法及其重载
  • 要求:必须保证在基类和派生类中的属性的定义格式完全一致,包括可访问性(访问修饰符)、返回值类型、属性名称、属性体;
public class Animal//基类
{
public virtual string Name//将属性虚拟,这是一个只读属性
{
get {
if(name=="" or name==null)
return "该动物未起名";
else
return name;
}}}

public class Dod:Animal
{
public overvide string Name//覆盖基类的虚属性
{
get{
if(name=="" or name==null)
return "该狗狗未起名";
else
return name;
}}}

访问基类的成员

基类与派生类之间的转换
  • C#允许把派生类转换为基类,但不容许把基类转换为派生类;
  • 当基类的对象指向派生类的实例时,系统将进行隐式转换,把数据类型从派生类转换为基类:如**Animal b=new Dog();**虽然b指向了派生类的实例,但他的数据类型还是基类,此时,若通过基类对象来调用一个基类与派生类都具有的同名的方法,则系统将调用基类的方法。
在派生类中调用基类的成员
  • 当派生类重载或覆盖基类方法后,若想在派生类中调用基类的同名方法,可以使用base关键字
public overvide void Eat()
{
base.Eat();
}

抽象类

  • 抽象类:在C#中,凡是包含无法实现的成员的类就是抽象类,其中那些无法实现的操作就是类的抽象成员。(抽象成员必须在抽象类中声明,但抽象类不要求必须包含抽象成员。)
  • 注意点:1.抽象类只能当作基类使用,而不能直接实例化;2.抽象类不能是密封或静态,只能用抽象关键字标识。
  • 用途:抽象类就是提供多个派生类可共享的基类的公共定义。

抽象成员

抽象方法
  • 抽象方法:指在基类的定义中,不包含任何实现代码的方法,就是没有代码的方法。作用:让派生类重写;
  • 声明:在C#中,抽象类和抽象方法使用***关键字abstract***声明;
public abstract class Shape//声明抽象类
{
protected double radius;
public Shape(double r)
{
radius=r;
}
public abstract double Cubage();//声明抽象方法,用来计算体积;
public abstract double Length//声明抽象可读写属性
{
get;
set;
}
}
抽象属性
  • 抽象属性:不提供具体实现,只声明该属性的数据类型、名字、可访问性等;(可以是只读、只写、写读)
  • 代码如上:

重载抽象方法属性

  • 在抽象类的派生类中,如果没有重载,那么派生类也必须声明为抽象类,即要有abstract关键字;
  • 重载格式:加overvide关键字;重载的方法名称和参数列表必须与抽象类中的方法完全一致;
public override 方法名称(参数列表){}

接口

  • 接口:是C#中的一种数据类型,属于应用类型。接口主要用来定义一个规则,让企业内部或行业内部的软件开发人员按标准去实现应用程序的功能。
  • 一个接口定义一个协定(就是签名格式)。接口可以包含方法、属性等成员,它只描述这些成员的签名(即成员的数据类型、名称和参数等),不提供任何实现的代码,具体实现由继承该接口的类来实现。
  • 继承接口的类:必须遵循该接口定义的协定,即必须按接口所规定的签名格式进行实现。
接口的声明
  • 在C#中,声明接口使用interface关键字
访问修饰符 interface 接口名//访问修饰符只能使用public\internal,默认为public可省略。
{//接口名以一般以I打头
//接口成员
}
  • 接口可以继承其他接口,基接口列表表示其继承的接口名。
  • 接口成员可以是属性、方法等,不能包含常量、字段、构造函数、析构函数等。
  • 所有接口成员隐式的具有了public访问修饰符,所以不能为接口成员添加任何访问修饰符。
interface Iusb
{
int MaxSpeed{get;}
string TransData(string From,string to);
}
接口的实现
  • 在C#中,一个接口的派生类必须实现该接口声明的所有成员。
public class Mp3:Iusb
{
public int MaxSpeed
{
get{return 480;}
}
public string TransData(steing from.string to)
{return string.Format("数据传输:从{0}到{1}",from,to);}
}
  • 在C#中,结构型也可以从接口派生。
  • 结构型和类的区别:在C#中结构型属于值类型,其不具有面向对象的特性,在继承上,仅限于从接口派生,无法从结构型派生一个新的结构型。而类属于引用类型,完全体现面向对象的思想。
接口的继承性
  • 接口派生:在C#中,一个接口可派生新的接口。接口支持多重继承(一个接口可以从多个基接口派生,基接口名之间用逗号分隔)。(类只支持单一继承)。
interface Iusb
{
int MaxSpeed{get;}
string TransData(string fron,string to);
}
interface Ibluetooth
{
int MaxSpeed{get;}
string TransData(string from,string to);
}
interface Imps:Iusb,Iblueytooth
{
string Play(string mp3);
}
多重接口的实现
  • 多重接口实现:就是在接口实现时,一个实现类可以从多个基接口派生。
public class Mobile:Iusb,Ibluetooth
{
//实现代码
}
  • C#允许一个类同时从基类派生(类的派生)和基接口派生(接口实现),但要求基类名在基接口名前。
public class Mobile:Phone,Iusb,Ibluetooth//Phone是一个基类,Iusb\Ibluetooth是接口
{
}
public abstrct class Phone //抽象基类
{
//接口的实现
public abstract string Call(string name);//抽象方法
}
public class Mobile:Phone,Iusb,Ibluetooth//派生实现类
{
int Iusb.MaxSpeed//当类继承多个接口时存在同名成员,就以此种形式区分(显示实现),不能带访问修饰符
{
get{return 480;}
}
string Iusb.TraansData(string from,string to)
{return string.Format("USB数据传输:从{0}到{1}",from , to);}
int Ibluetooth.MaxSpeed
{
get{return 64;}
}
string Ibluetooth.TransData(string from,string to)
{return string.Format("蓝牙数据传输:从{0}到{1}",from ,to);}
//抽象类的继承
public override string Call(string name)
{return string.Format("正在和{0}通话中。。。",name);}
}
访问接口的成员
访问接口的成员
  • 访问接口的成员:就是说,在接口的派生类实现接口的所有成员之后,来访问这些成员。
  • 访问方式:1.通过派生类的实例来访问。2.通过接口的实例来访问。
    1.通过派生类的实例:
Mp3 m=new Mp3();
lblShow.Text=m.TransData("计算机","MP3设备");

2.通过接口的实例来访问:(better)
接口的实例化:接口是不能直接实例化的,只能间接实例化。先创建其派生类的对象,在将该对象强制转换为接口类型并赋给接口变量,从而创建接口的实例)

Mp3 m=new Mp3();
Iusb u=(Iusb)m;
lblShow.Text=u.TransData("计算机","MP3设备");
测试对象是否支持接口(测试类是否实现了接口)
  • 测试派生类的对象是否实现了接口:由于我们无法预知实例化的类是否已经实现了接口,如没有实现,但访问接口的成员,就会造成程序异常。

  • 方法:1.is 2.as
    1.表达式 is 接口
    (此为判断)

Mp3 m =new Mp3();
if(m is Iusb)//判断表达式
{
Iusb u =(Iusb)m;
lblShow.Text=u.TransData("计算机","Mp3设备");
}
  1. 表达式 as 类型
    (转换加判断:首先测试转换是否合法,若是则进行转换,否则返回null)
Mp3 m=new Mp3();
Iusb u =m as Iusb;
if(u!=null)
{
lblShow.Text=u.TransData("计算机","Mp3设备");
}

知识梳理

  • 静态成员就是那些属于类但是不属于对象的成员,静态类就是只有静态成员的类。
  • 类的继承性,就是基类派生子类的过程。
  • 类的多态性:在继承性基础上,子类对于基类的成员的替换或覆盖。
  • 抽象类:就是一个类中有些成员无法用代码实现,就可将其类和此成员抽象,就是只有形式,没有实现代码,在抽象类的派生类中,可将抽象成员实现,也可不实现。注意,抽象类中由抽象成员有不抽象成员。
  • 接口:就是定义了一个规范,实则就是接口中所有成员都只有形式没有实现代码,在派生类中需要全部实现。

嵌套类、分布类与命名空间

嵌套类
  • 嵌套类:在类的内部或结构的内部定义的类型称为嵌套类型/内部类型。默认为private。
    看例子
分布类
  • 分布类:分布类允许将类、结构、接口的定义拆分到两个或多个源文件中,让每个源文件只包含其中的一部分代码,编译时C#编译器自动会把所有部分组合起来进行编译;
  • c#中,分布类用partial关键字修饰;
  • 分布类注意:1.各个部分的访问修饰符必须相同。2.同一类型的各部分的所有分布类的定义都必须在同一程序集或同一模块。3.可独立引用类库。4.分布类的定义中允许使用嵌套的分布类。5.部分抽象/密封,则整体抽象/密封。
命名空间
  • 自定义命名空间:
namespace 名字
{
//类型的声明
}
  • 引用命名空间的类:
    1.采用完全限定名来引用:
    Sohu.Sales.Customer c = new Sohu.Sales.Customer();
    2.首先通过using关键字导入命名空间,再直接引用:
    using Sohu.Sales;
    Customer c=new Customer();

(俺的天哪,终于写完啦。)

参考书籍和网站

  • 书籍:《C#程序设计经典教程》 罗福强等主编
  • 网站:百度
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值