0X1 引言
提起面向对象,每个人都有不同的见解。但提的最多的无非就是:对象、封装、继承、多态。差不多就是这些元素构成了面向对象设计开发的基本逻辑。面向对象编程,“对象”指的是什么?这里的"对象"可不是指“异性对象”,而是我们在开发中常常使用的:类。
0X2 对象
出生:对象就像个人的人,生而入世,死而离世。首先我们看看一个对象是如何产生的呢?在执行New操作后,系统首先会在内存中为其分配一定的内存空间,然后初始化其附加成员,调用构造函数执行初始化,这样一个函数就完成了初始化。
Person person=new Person("大壮他哥",25);
旅程:在某种程度上就是外界通过方法与对象交互,从而达到改变对象状态信息的过程。这也和人的生存之道暗合。
person.ChangeAge(26)
权限:我们都知道继承,儿子可以继承父亲的姓氏、基因、财产和一切可以遗留的东西,但并不代表就可以继承所有。因为父亲有一些隐私的部分为父亲独有,不可继承。所以,我们就需要在程序中标识哪些可继承或不可继承(这里的继承可以理解为访问权限)。.Net框架为我们内置了五种访问权限:
- public:最高访问权限,公司的董事会具有最高的决策权与管理权;
- protected:部门经理,具有对本部门的直接管辖权,面向对象中体现为子类继承纵向关系的访问约定;
- internal:类似于公司的职能部门的职责,不管是否具有上下级关系,人力资源部都有管辖其他部门员工的能力;(面向对象中体现为同一程序集的访问权限,只要是隶属于同一程序集,对象即可访问其属性等,不管是否存在隶属关系;)
- protected internal:副总经理,从横向到纵向都有管理权;
- private:最低访问权,公司一般职员,管好自己即可;
0X3 继承
什么是继承?
图1 继承关系图
继承,就是类与类之间的一种关系。继承的类成为子类(图1中小车和飞机就成为子类)、派生类。而被集成的类则成为父类、基类或超类。通过集成,使得子类拥有父类中允许继承的属性和方法。同时子类也可以添加新的方法或者属性在建立一个新的类层次。
继承的实现与本质?
图2 继承的实现
如图2所示的这个继承体系中,Vehicle为所有交通工具的基类,其定义了所有交通工具都具备的"启动"和"停止"方法。其中Aricraft类实现了IFlyable接口,使得Aricraft可以实现Fly()这一特性。这样的好处是显而易见的,通过IFlyable接口,实现了对象与行为的分离,这样我们就无需担心继承不当而导致Car也拥有了Fly()的能力,保护了系统的稳健性。
public class Vehicle { public virtual void Start() { Console.WriteLine("Vehicle is Start"); } public virtual void Stop() { Console.WriteLine("Vehicle is Stop"); } } public class Car: Vehicle { public override void Start() { Console.WriteLine("Car is Start"); } public override void Stop() { Console.WriteLine("Car is Stop"); } } public class Aircralt : Vehicle, IFlyable { public void Fly() { Console.WriteLine("Aircralt is Fly"); } } public interface IFlyable { void Fly(); } static void Main(string[] args) { Vehicle car = new Car(); car.Start(); Console.ReadLine(); }
代码演示
我们来简单分析一下对象的创建过程:
Vehicle car = new Car();
Vehicle car是创建一个Vihicle类型的引用,而new Car()则是创建一个Car对象,分配内存空间和初始化操作,然后将这个对象的引用赋给car变量,也就是建立car变量和Car对象的关联。我们从继承的角度来分析CLR在运行时如何执行对象的创建过程的。我们以car为例,car对象一经建立,首先会利用递归查找到其父类,并为父类分配存储空间。对象的创建过程是按照顺序完成了对整个父类以及本身字段的内存创建。并且字段的存储顺序是由上到下的排列,最高层地的排在上。其原因是如果父类和子类出现了同名的属性,编辑器会自动认为这是两个不同的字段而加以区别。然后是方法表的创建,需要注意一点的是方发表的创建在是类第一次加载到AppDomain是完成的。在创建对象的时候只是讲对象的TypeHandle指向方发表的Loader Heap上,也就是说,方法表是在先于对象创建存在的。类似于字段的创建过程,方法表的创建也是先父类后子类的。在创建子类方法表的时候会先从其最高级别的父类向下递归。首先把父类的所有的虚方法Copy一份,然后和子类方法表做对比,如果有重写操作则以子类的方法覆盖父类的方法。同时添加父类的非虚方法,从而完成car方法表的创建。
从我们的分析和上面创建对象的过程中,我们对继承应有了以下更明确的认识:
- 继承是可以传递的,子类是对父类的扩展,必须继承父类方法,同时可以添加新方法。
- 子类可以调用父类的方法和字段,但是!父类不能调用子类的方法和字段。
- 子类不光继承父类的共有成员,同时也继承了父类的私有成员,只是在子类中访问不到。(不知道可否通过反射访问到。。。。希望可以一起探讨这个问题。)
继承的分类与规则?
继承的分类可以分为两种:实现继承与接口继承
实现继承与接口继承的区别:
抽象类适合于有族层概念的类间关系,而接口最适合为不同的类提供通用功能
接口着重于CAN-DO关系类型,而抽象类则偏重于IS-A式的关系
接口多定义对象的行为;抽象类多定义对象的属性
版本式的问题最好以抽象类来实现
因为值类型是密封的,所以只能实现接口,而不能继承类