1. 程式人生 > >【鏈塊技術54期】智慧合約基礎語言(九)——Solidity繼承

【鏈塊技術54期】智慧合約基礎語言(九)——Solidity繼承

原文連結:以太坊智慧合約(九):Solidity繼承

 

本文主要講解了有關智慧合約繼承的概念、繼承的引數傳遞、重寫函式以及Solidity的繼承中的呼叫關係與多繼承。掌握區塊鏈技術,學習智慧合約。

 

一、目錄

☞繼承的概念

☞繼承的引數傳遞

☞重寫函式

☞Solidity的繼承中的呼叫關係與多繼承

二、繼承的概念

Solidity語言為我們提供了繼承的支援,實現的方式是通過複製包括多型的程式碼到子類來實現的。
繼承通過關鍵字is來實現,一起來看看下面的例子:

上面的例子中,合約Manager繼承了Person合約。

繼承的合約Manager可以訪問所有的非私有成員。包括internal的函式和狀態變數(這些是不能通過external的方式訪問的,如this.yourFunc()),我們來看下面的例子:

從上面的例子中,我們可以看到,子類可以訪問父類的public,internal許可權控制變數或函式,不能訪問private許可權控制的變數和函式。在子類中可以直接訪問狀態變數,原因是因為狀態變數預設是internal的。

三、繼承的引數傳遞

繼承支援傳參,繼承時可以有兩種方式傳引數到父類。下面來看第一種方式:

另外一種方式是類似修改器的語法,來直接看一個例子:

如果要傳入到基類的是簡單的常量,第一種方式會更加簡潔。但如果傳入的引數與子類的輸入引數有關,那麼你應該使用第二種方式,以獲取引數值。如果你同時使用了這兩種方式,後一種方式將最終生效。

四、重寫函式 

在子類中允許重寫函式,但不允許重寫返回引數的型別,一起來看看下面的程式碼:

 

上面程式碼中的function data() returns(string){}將導致Override changes extended function signature報錯,因為不能修改返回的引數型別。

五、Solidity的繼承中的呼叫關係與多繼承

 在繼承鏈中,由於繼承實現是程式碼複製。如果出現函式重寫(類似其它語言的函式過載),最終使用的是繼承鏈上哪個合約定義的程式碼呢?實際執行時,依據的是最遠繼承的原則(most derived)。下面來看一個例子:

上面的例子中,根據最遠繼承原則,大家可以想想MostDerived1,和MostDerived2中呼叫call()方法的執行結果。

實際上呢,MostDerived1,MostDerived2的call()將分別返回2和1。因為對於MostDerived1的最遠繼承合約是Base2,所以會使用其對應的函式,對於MostDerived2最遠的繼承者將是Base1。

5.1 指定呼叫父合約方法

雖然存在最遠繼承原則,但是我們仍可以在子合約中主動呼叫父合約被重寫的方法來觸發被覆蓋的函式。下面來看一個清理的例子:

因為三個合約的繼承關係是:SpecifyBase <= mortal <= owned,所以SpecifyBase中可以直接呼叫父級mortal的kill。如果不指定那麼SpecifyBase中的kill僅相當於重寫父級的kill函式。在SpecifyBase我們打算完成一些特有的清理流程,但想複用父合約的清理流程,可以通過mortal.kill()的方式直接呼叫父合約的函式。

5.2 super關鍵字

當我們在進行一些清理的時候,有些時候,我們希望繼承鏈條上每一個函式都能被呼叫以進行一些清理工作,這個時候,我們需要用到super關鍵字,繼續來看一個更多複雜的清理流程的程式碼:

上面的例子中,在Final中呼叫kill(),將僅僅觸發Base2.kill()被呼叫,因為它是最遠繼承合約,從而跳過Base1.kill()。如果我們想也觸發Base1.kill(),解決方案是使用super。

在上面的程式碼中,我們呼叫FinalWithSuper的kill()方法,將觸發按最遠繼承原則形成的鏈 Final,Base2,Base1,motal,owned的呼叫,上述程式碼執行的事件如下:

這樣我們就實現了對鏈條上的所有方法的呼叫。另外,不知大家是否已經注意到,在使用super的上下文中,實際並不知道最終的呼叫鏈是如何的,還與繼承的關係有關。

5.3 多繼承與線性化

在Solidity中,允許多繼承,你可以同時繼承多個合約。實現多繼承的程式語言需要解決幾個問題,其中之一是菱形繼承問題又稱鑽石問題(假設我們有類B和類C,它們都繼承了相同的類A。另外我們還有類D,類D通過多重繼承機制繼承了類B和類C,因此D從理論上來講有兩份A的屬性和方法。因為上述圖表的形狀類似於鑽石(或者菱形),因此這個問題被形象地稱為鑽石問題(菱形繼承問題))。如下圖。

 

Solidity的解決方案是根據is後面的合約順序來線性化繼承關係,即overwrite的順序可以是,D < B < C < A, 也可以是 D < C < B < A。因此在D裡面只會有一個同名屬性或者函式的副本,而不會出現菱形問題的兩個副本並存的情況。 下面的程式碼,Solidity會報錯Linearization of inheritance graph impossible。

原因是C會請求X來重寫A(因為繼承定義的順序是A,X),但A自身又是重寫X的,所以這是一個不可解決的矛盾。

一個簡單解決這種矛盾的原則是,總是指定基合約的繼承順序是從most base-like到most derived。總之, 按照既定的順序繼承就不會有問題, 先繼承祖父的再繼承父親。

 


-END-