C#面向对象学习笔记(一)

这几天,项目比较空一点,正在重点看一下C#基础语法,感觉面向对象那一部分,有些地方还是满疑惑的。

参考了《C#高级编程》第四版   第3和4章  边看边总结了点笔记

 

C#中的继承(第4章 继承)
1.继承的类型
(1)实现继承
表示一个类型派生于一个基类型,拥有该基类型的所有成员字段和函数

(2)接口继承
表示一个类型只继承了函数的签名,没有继承任何实现代码。
接口继承通常被看作提供了一种契约,让类型派生于接口,来保证为客户提供某个功能

(3)多重继承
C#不支持多重继承,C#允许类型派生于多个接口
System.Object是一个公共基类,所以每个C#类(除Object),都有一个基类,还可以有任意多个基接口

(4)定义结构和类的总结:
结构总是派生于System.ValueType,还可以派生于任意多个接口
类总是派生于用户选择的另一个类,还可以派生于任意多个接口

2.实现继承
class A:B    A类派生于B类
{

}

class A:B,IInterface1,IInterface2   同时也派生于接口
{

}

其实,如果在类定义中没有指定基类,C#编译器就假定System.Object是基类
C#支持object关键字,作为System.Object类的假名

 

(1)虚方法
把基类声明为virtual,那么该方法就可在任何派生类中重写
public virtual string xxxxMethod(){

}

也可以把属性声明为virtual
public virtual string xxxxx
{
get{....}
set{....}
}

C#中虚方法可以在派生类中重写,在调用方法时,会调用对象类型的合适方法
派生类重写虚方法时要使用override关键字显式声明
成员字段和静态方法都不能声明为virtual

(2)隐藏方法
如果签名相同的方法在基类和派生类中都声明,但该方法没有声明为virtual和override
那么派生类方法会隐藏基类方法

同时C#会给出警告,使用new关键字声明要隐藏一个方法
在派生类方法前使用new,则可以关闭这个警告

当派生类方法前使用了new,而实际上该方法并没有覆盖基类的方法,那么编译器也会发出警告

(3)调用方法的基类版本
派生类中调用方法的基类版本:base.MethodName()
也可以使用base() 来调用基类构造函数

以上主要讨论了基类,派生类的方法,其规则也使用于属性

 


(4)抽象类和抽象方法
abstract关键字

抽象类不能实例化
抽象方法没有实现代码,必须在非抽象的派生类中重写(实际上抽象方法也是虚的,但不需要提供virtual)
如果类包含抽象方法,那么该类也是抽象的,也必须声明为抽象的 abstract


(5)密封类和密封方法
sealed关键字
对于类来说表示不能继承该类

对于方法来说表示不能重写该方法
注意:在方法上使用sealed是没有意义的,除非该方法本身是某个基类上另一个方法的重写形式
如:
class MyClass
{
 public sealed override void MethodA(){}   //MethodA方法在基类中已经是一个重写形式
}
//这里的sealed 关键字其实就是确保了MethodA在此处重写的代码是最终版本,其它人不能再重写它了

class TowClass:MyClss
{
 public override void MethodA(){}   //错误,因为MethodA方法不能被重写
}


如定义一个新方法不想让别人重写,则首先就不要声明为virtual

 

(6)派生类的构造函数
当没有为类定义任何显式的构造函数,编译器会为所有的类提供默认的构造函数,并且能够很好的
解决类层次结构中的所有问题

基类
abstract class BaseA
{
 private string name;
}


子类
class A:BaseA
{
 private int id;
}

描述实例化派生类时发生的情况:
假定默认的构造函数在整个层次结构中使用
编译器首先找到它试图实例化的类的构造函数,是A,而这个默认 A构造函数首先是为其直接基类BaseA运行默认
构造函数——》BaseA构造函数同样继续为其直接基类System.Object运行默认构造函数
而System.Object没有任何基类,其构造函数执行,并把控制返回BaseA——》执行BaseA构造函数,将name初始化为null
控制权返回给A——》执行A构造函数,将id初始化为0,并退出

注意:构造函数的调用顺序是先调用System.Object,再按照层次结构由上向下进行,直到编译器要实例化的类为止
每个构造函数都初始化它自己类中的字段


添加构造函数
第一:在层次结构中添加无参数的构造函数(用无参数的构造函数替换默认构造函数)
比如,要将上述BaseA class中的name初始化为"no name"
public abstract class BaseA
{
 private string name;
 public BaseA():base()  //:base() 表示添加了一个对基类构造函数的调用
 {
  name="no name";
 } 
}


当然针对此类,:base() 则可以不写
因为编译器在构造函数的“{”前面没有找到对另一个构造函数的任何引用,就会假定我们要调用基类构造函数
对于此类 事实上都是调用System.Object构造函数


第二:在层次结构中添加带参数的构造函数
如:

public abstract class BaseA
{
 private string name;
 public BaseA(string name)
 {
  this.name=name;
 } 
}

这样的情况,则在实例化A的时候,编译出错,因为编译器为A生成的默认构造函数会试图调用无参数的
BaseA构造函数,而由于BaseA中定义了带参数的构造,所以BaseA中没有默认的构造函数了.
因此,需要为派生类也提供一个带参数的构造函数来避免错误
如:
 
class A:BaseA
{
 private int id;

 //A构造函数本身不能实例化name字段(不能访问基类中私有字段),但可以把name传给基类
 public A(string name):base(name)
 {
 }
}

 

第三:重载构造函数和一个类的层次结构
如:
class A:BaseA
{
 private int id;
 private refName;
 
 //构造函数1
 public A(string name,string refName):base(name)
 {
  this.refName=refName;
 }

 //构造函数2
 public A(string name):this(name,"none"){
  
 }
}

当执行 A a=new A("Hello");就会调用 构造函数2 ,之后立即把控制权传给对应的 构造函数1,这个函数带2个参数
分别是"Hello"和"none";在这个构造函数中依次把控制权传给BaseA构造,该构造带有1个参数——字符串"Hello".
然后继续——》System.Object默认构造函数

开始执行构造函数:首先System.Object构造函数——》执行BaseA构造函数,初始化name
——》2个参数的A构造,初始化refName为"none"——》执行1个参数的A构造(什么也不做)


在为类编写自己的构造函数时遵循上述规则,则可以避免任何问题,顺利初始化

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值