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裏就能夠被實例直接調用,若是是別的權限也寫到對應的權限裏。
相關文章
相關標籤/搜索