Ruby中的继承、原型、面向对象、访问域

先有类仍是先有对象

  • 从鸡蛋悖论解决能够悟到一个道理,不要从常识上假设非此即彼和绝对静止。
  • Ruby中的类和对象正是这么个东西
    1. 咱们建立一个类,那它就是Class这个对象的实例,而Class,因而咱们以为是对象产生了类,因此类都是对象
    2. 当咱们用类建立一个对象,咱们就发现对象是类的实例化,甚至OВJect.class 也返回Class, 因此能够说类产生了对象
    3. 因为一、2,咱们就产生一个悖论疑惑:在Ruby里最初的那个东西究竟是类仍是对象啊?
  • 答案是,Class、Medule、OВJect、BasicOВJect这些东西并无谁产生谁的说法,他们都是虚拟机在最初生成的结构体而以,考虑这样的C语言实现:
    1. 定义一个基本结构体:
    struct BasicOВJect{
    		long id;
    		char* name;
    		struct BasicOВJect *class;
    		struct BasicOВJect **ancestors;
    	}
    1. 而后定义了Class,OВJect
    2. 而后赋值
    Object.class = &Class;
    	class.ancestor = (strct BasicOВJect**)malloc(sizeof(*BasicOВJect)*128);
    	class.ancestor[0] = &Class;
    1. 按咱们本身的想法就作出来了Class、OВJect两个东西,而且Class好像是OВJect产生的,由于OВJect是Class的ancestor,而OВJect又好像是Class的实例,由于它的class显示是OВJect。

原型机制

虽然在现有对象仍是先有类上咱们不用纠结了,可是继承和实现对于咱们使用Ruby是很实在的问题,确实咱们遇到的对象都是类的实例,也确实咱们遇到的类都是Class这个对象产生的。咱们只须要搞清楚基本的继承机制。函数

  1. 全部类都是对象,全部对象都有个单类。
  2. 类都有一个new方法,可是Class.new比较特殊:
    • 它返回的对象是类,可是Class的new方法并无被这些类继承,而是定义了一个不同的new给了它们。
      • 不同的地方有:Class的new并无将本身加入它实例的ancestor中,而普通类都会这么作
  3. 全部对象都有一个单例,单例是个类,里面开辟了这个对象的独立状态空间,用 def A.method 这样定义的方法都是单例方法。
    • 当显示调用一个方法,就涉及到方法查找。用Ruby的语言来讲,就是当前self成为sender,向 "." 左边的对象发送函数名称的Symbol做为消息,因此左边对象被叫作receiver。
    • 方法查找的顺序和JS很类似,都是经过原型链,不同的是它是先进入单例,在单例里面找方法,没找到再在单例的Ancestor里面往上查,注意全部的Ancestor都是类,方法查找,是在它们的实例方法里找;另外一个不同的是所谓mix in,因此并非一条直线,而是相似多重继承。找到方法以后还要看访问权限。
      • 访问权限若是是 public,那就直接调
      • 反问权限若是是 private,很差意思,不支持显式调用,报错
      • 访问权限若是是 protected,那要看 当前self是否是receiver的子孙,准确的说看sender的class是否是receiver的class的子类,也就是说只容许在子类的定义里面调用。(这里官方文档貌似描述有误,官方文档说 receiver是sender的subclass也能够,但实际上它给的例子就证实了不行,也就是说protected的权限是向下继承的)
  4. 注意上面的访问权限,Ruby和别的语言在访问权限上是有区别的,Ruby的访问权限都是实例的权限,好比在一个类中定义一个实例方法,默认访问权限是public,但这是对它的实例而言的,对于这个类自己,这个方法被存放在instance_methods里,即再也不单例方法也不在 私有、公开、保护方法里,因此调用找不到。而经过new建立实例的时候,类的instance_methods就被写到了实例的方法空间里了,当是public就写到public_methods里就能够被实例直接调用,若是是别的权限也写到对应的权限里。
相关文章
相关标签/搜索