1.可以通过override重写父合约virtual函数
pragma solidity ^0.8.0;
contract Base1{
function data() virtual public pure returns(uint) {
return 1;
}
}
contract Base2{
function data() virtual public pure returns(uint) {
return 2;
}
}
contract MostDerived1 is Base1, Base2{
// 必须重载data()函数因为Base1 和 Base2都有data函数
function data() public override(Base1,Base2) pure returns(uint){
return 3;
}
// 返回1
function call1() public pure returns(uint){
return Base1.data();
}
// 返回2
function call2() public pure returns(uint){
return Base2.data();
}
// 返回3
function call3() public pure returns(uint){
return data();
}
}
2.继承链中不能有相同的变量名
pragma solidity ^0.8.0;
contract Base1{
uint256 public data1 ;
function data() virtual public {
data1 = 1;
}
}
contract Base2{
uint256 public data1 ;
function data() virtual public {
data1 = 2;
}
}
contract MostDerived1 is Base1 , Base2{
function data() virtual override public {
}
}
编译会报错:
3.重写遵循最远继承原则
通过super调用只会执行一个
pragma solidity ^0.8.0;
contract Base1{
uint256 public data1 ;
function data() virtual public {
data1 = 1;
}
}
contract Base2{
uint256 public data2 ;
function data() virtual public {
data2 = 2;
}
}
contract MostDerived1 is Base1 , Base2{
// 只会执行Base2.data
/*
在继承链中,由于继承实现是代码复制。如果出现函数名重写,最终使用的是继承链上哪个合约定义的代码呢?实际执行时,依据的是最远继承的原则(most derived),即使用最后出现的Base2.data()
*/
function data() virtual override(Base1 , Base2) public {
super.data();
}
// Base1.data 和 Base2.data都会执行
function data() virtual override(Base1 , Base2) public {
Base1.data();
Base2.data();
}
function data() virtual override(Base1 , Base2) public {
Base1.data();
super.data();
}
}
4.使用super 会依照最远继承链的形式依次执行继承链中的函数
pragma solidity ^0.8.0;
contract owned {
address public owner;
constructor() { owner = msg.sender; }
}
contract mortal is owned {
event mortalCalled(string);
function kill() public virtual {
emit mortalCalled("mortalCalled");
if (msg.sender == owner){
owner = address(0x1);
}
}
}
contract Base1 is mortal {
event Base1Called(string);
function kill() public virtual override {
/* do cleanup 1 */
emit Base1Called("Base1Called");
super.kill();
}
}
contract Base2 is mortal {
event Base2Called(string);
function kill() public virtual override{
/* do cleanup 2 */
emit Base2Called("Base2Called");
super.kill();
}
}
contract FinalWithSuper is Base1, Base2 {
function kill() public virtual override(Base1 , Base2){
/* do cleanup 2 */
emit Base2Called("FinalWithSuperCalled");
super.kill();
}
}
事件触发顺序:
在上面的代码中,我们调用FinalWithSuper的kill()方法,将触发按最远继承原则形成的链 Final,Base2,Base1,motal,owned的调用
5.多继承与线性化(Multiple Inheritance and Linearization)
pragma solidity ^0.8.0;
contract X {}
contract A is X {}
contract C is A, X {}
error reson:
对于C合约来说按照最远继承原则,X会重写A
对于A合约来说,A继承于X,所以A会重写X
因此造成冲突
解决:
pragma solidity ^0.8.0;
contract X {}
contract A is X {}
contract C is X, A {}
6.合约会依次执行继承合约的构造函数
pragma solidity ^0.8.0;
contract Base1{
uint256 public data1 ;
constructor() {
data1 = 1;
}
}
contract Base2{
uint256 public data2 ;
constructor() {
data2 = 2;
}
}
contract MostDerived is Base1 , Base2{
// data1=1
// data2=2
}
7.变量存储位置与继承顺序
pragma solidity 0.8.0;
contract storageValue1{
uint256 public a ;
constructor(){
a =1;
}
}
contract storageValue2{
uint256 public b ;
constructor(){
b =2;
}
}
contract storageVal is storageValue1 , storageValue2{
// 1
function getSlot0() public view returns(uint256 res){
assembly{
res := sload(0)
}
}
// 2
function getSlot1() public view returns(uint256 res){
assembly{
res := sload(1)
}
}
}
结论:按照继承顺序继承