基於地址類型轉換問題的合約多態性
我是剛接觸solidity 的新手,很難理解多態性和契約的類型轉換。
我將child_1契約的地址傳遞給getChild2Value(address adr),後者將地址類型轉換為child_2契約。它是否應該在我發送child_1地址並將其類型轉換為child_2時不引發錯誤或異常,而是從 child_1 函式獲得返回。
謝謝。
編譯指示 ^0.8.0;
contract parent{ function getValue( ) public view virtual returns(uint) { return 10; } } contract child is parent{ function getValue( ) public view override returns(uint) { return 15; } } contract child_2 is parent{ function getValue( ) public view override returns(uint) { return 20; } } contract ContractPolymorphism { function getChildValue(address adr) public view returns(uint){ return child(adr).getValue(); } function getChild2Value(address adr) public view returns(uint){ return child_2(adr).getValue(); } }
我將 child_1 契約的地址傳遞給 getChild2Value(address adr)。它是否應該在我發送 child_1 地址並將其類型轉換為 child_2 時引發錯誤或異常
我認為您期待類型安全的響應,但部署的契約實例不支持該響應。換句話說,部署的合約不會被轉換為不同的類型。它們只是帶有字節碼的地址。換句話說,類型安全是一種編譯時特性,不會擴展到已部署的合約。
這就是說,從地址“adr”的“子”合約返回函式“getValue”的響應:
return child(adr).getValue();
它可以
child(adr)
毫無怨言地通過,因為它將接受任何地址並為其分配契約中child
定義的類型。您對此類型的內部描述不必完整,也不一定準確。當您嘗試與合約互動時,不准確的地方就會開始出現。它可以毫無問題地通過函式呼叫。
child(adr).getValue()
從
ContractPolymorphism
關於這個外部合約的唯一相關資訊的角度來看,函式簽名和合約地址。它需要知道的一切都在編譯器製定的這個介面描述中擷取:function getValue() external view returns(uint);
兩個版本中都存在相同的功能,
child
因此按預期發送消息並接收響應。為了說明繼承和組合是如何工作的,請考慮以下一組契約:
interface IERC20 { ... // minimal contract ERC20 is IERC20 { ... // everything important contract TokenA is ERC20 { ... // instances contract TokenB is ERC20 { ... contract TokenC is ERC20 { ... contract WorkWithAnyToken { // when a contract is a function param, externally it is an address // and internally, it is cast as a contract. function withFromAny(IERC20 token, uint amount) public ... token.transfer(msg.sender, amount); } }
分解它:
- 該介面具有未定義的功能。它列出了外部介面。
- 履行承諾。通過繼承介面,我們知道除非定義了介面的所有功能,否則它不會部署。
- 製作代幣很容易。它們都可以具有獨特的屬性,但必須實現相同的基本功能,並且我們知道基本介面沒有偏離。
- 我們可以製作一個與介面抽像一起工作的函式(它不需要實際令牌的所有程式碼 - 只需要介面)。我們需要一個地址來實例化令牌。我們可以
function foo(address bar) ... { IERC20 token = IERC20(bar);
在函式參數中將其轉換為 IERC20。從外部看,沒有區別。它始終是一個地址,因為 ABI 不支持像合約這樣的複雜類型。它是內部類型安全的 - 在編譯時檢查。重要的是,沒有檢查傳入的地址是三個定義的代幣之一,甚至是其他人的 ERC20 合約。是的,您可以使用 IERC20 來實例化 ERC20。您只是在說“這是在地址上與合約對話的方式”。因此,如果您想將輸入的地址限制為“受信任的”合約,那麼您的合約需要一個白名單,並且您的函式需要在互動之前進行檢查。
如果沒有這樣的功能,在互動階段就會出現問題。如果您盲目地信任並且結果證明它不是預期類型的實例,則會導致執行時錯誤。
對於咯咯笑,考慮一下這種匯總這些觀點的安排。部署父母和家庭。然後敲擊父級以部署子級。查看事件日誌中的子地址。與家人一起檢查:
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.7.4; interface IChild { function birthday() external view returns(uint); } contract Child is IChild { uint public override birthday; constructor() { birthday = block.timestamp; } } contract Parent { event NewChild(Child child); function newChild() public returns(Child child) { child = new Child(); emit NewChild(child); } } contract Family { // The interface is more compact than the implementation which makes this contract smaller. // We're only concerned with the message format so the contracts can talk. function getBirthday(IChild child) public view returns(uint birthday) { return child.birthday(); } }
希望能幫助到你。