本文主要讲不规则继承下合约的插槽问题和调用函数问题钻石继承的插槽问题试问现在有上图这样的继承关系,abcd中各有一个变量,请问他们在插槽中的顺序是什么样的这要取决于D是在继承bc时的写法contractDisB,C{如果是这样写的,那么b的变量就排在c的变量前面,此时可以把c当
title: 继承 date: 2024-06-13 16:58 tags: null
本文主要讲不规则继承下合约的插槽问题和调用函数问题
钻石继承的插槽问题
试问现在有上图这样的继承关系,abcd中各有一个变量,请问他们在插槽中的顺序是什么样的
这要取决于D是在继承bc时的写法
contract D is B ,C{
如果是这样写的,那么b的变量就排在c的变量前面,此时可以把c当作b的父合约,如果想使用b中的变量,就需要两个super,但仅限于在d合约中是这样
pragma solidity ^0.8.22;
import "hardhat/console.sol";
contract A{
string public a;
function setString(string memory m) external virtual {
a=m;
}
function setTime()public virtual {
console.log(unicode"a");
}
}
contract B is A{
string public b;
function setString(string memory m) external override virtual {
b=m;
}
function setTime()public override virtual {
console.log(unicode"b");
}
}
contract C is A{
string public c;
function setString(string memory m) external override virtual {
c=m;
}
function logFather() external {
super.setTime();//b
}
}
contract D is B ,C{
string public d;
E e;
function setString(string memory m) external override(B,C) {
d=m;
}
function dele(address ee,uint num)external returns (bytes memory){
(bool iscom,bytes memory data)=ee.delegatecall(abi.encodeWithSignature("hootString(uint256)",num));
return data;
}
//每一个函数都必须
function setTime()public override (B,A) {//必须指名所有直接基类合约
console.log(unicode"d");
}
}
验证:我们编译部署上面的合约,并调用logFather函数,得到的结果是b
如果是更复杂的继承关系,该如何确定呢? 这里需要介绍c3线性化 以这个图中的继承关系为例,我们如何确定继承的顺序
令L(x)=[x]+merge(L(a),L(b),L[c]...,[a,b,c...])//其中abc都是x的直系父合约
那么图中
L(O) := [O]
L(A) := [A] + merge(L(O), [O])
= [A] + merge([O], [O])
= [A, O]
L(B) := [B, O]
L(C) := [C, O]
L(D) := [D, O]
L(E) := [E, O]
L(K1) := [K1] + merge(L(C), L(B), L(A), [C, A, B])
= [K1] + merge([C, O], [B, O], [A, O], [C, A, B]) //如果某个元素在merge数组中仅作为第一个元素,那么这个元素会被提取出来,比如这里的c,在第一个和最后一个数组中都是第一个元素,且其他数组没有c,那么c就会被提取出来,放在前面
= [K1, C] + merge([O], [B, O], [A, O], [A, B])
= [K1, C, A] + merge([O], [B, O], [O], [B])
= [K1, C, A, B] + merge([O], [O], [O])
= [K1, C, A, B, O]
L(K3) := [K3] + merge(L(A), L(D), [A, D])
= [K3] + merge([A, O], [D, O], [A, D]) // select A
= [K3, A] + merge([O], [D, O], [D]) // fail O, select D
= [K3, A, D] + merge([O], [O]) // select O
= [K3, A, D, O]
L(K2) := [K2] + merge(L(B), L(D), L(E), [B, D, E])
= [K2] + merge([B, O], [D, O], [E, O], [B, D, E]) // select B
= [K2, B] + merge([O], [D, O], [E, O], [D, E]) // fail O, select D
= [K2, B, D] + merge([O], [O], [E, O], [E]) // fail O, select E
= [K2, B, D, E] + merge([O], [O], [O]) // select O
= [K2, B, D, E, O]
L(Z) := [Z] + merge(L(K1), L(K3), L(K2), [K1, K3, K2])
= [Z] + merge([K1, C, A, B, O], [K3, A, D, O], [K2, B, D, E, O], [K1, K3, K2]) // select K1
= [Z, K1] + merge([C, A, B, O], [K3, A, D, O], [K2, B, D, E, O], [K3, K2]) // select C
= [Z, K1, C] + merge([A, B, O], [K3, A, D, O], [K2, B, D, E, O], [K3, K2]) // fail A, select K3
= [Z, K1, C, K3] + merge([A, B, O], [A, D, O], [K2, B, D, E, O], [K2]) // select A
= [Z, K1, C, K3, A] + merge([B, O], [D, O], [K2, B, D, E, O], [K2]) // fail B, fail D, select K2
= [Z, K1, C, K3, A, K2] + merge([B, O], [D, O], [B, D, E, O]) // select B
= [Z, K1, C, K3, A, K2, B] + merge([O], [D, O], [D, E, O]) // fail O, select D
= [Z, K1, C, K3, A, K2, B, D] + merge([O], [O], [E, O]) // fail O, select E
= [Z, K1, C, K3, A, K2, B, D, E] + merge([O], [O], [O]) // select O
= [Z, K1, C, K3, A, K2, B, D, E, O]
最后得到的这个数组就是继承顺序,可以看到,第一排merge中的顺序是根据继承时写的顺序来的
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!