Solidity智能合约开发 — 3.3-合约的事件和继承

1. 事件

Solidity中的事件(event)是EVM上日志的抽象,它具有两个特点:

  • 响应:应用程序(ether.js)可以通过RPC接口订阅和监听这些事件,并在前端做响应。
  • 经济:事件是EVM上比较经济的存储数据的方式,每个大概消耗2,000-5,000 gas不等。相比之下,存储一个新的变量至少需要20,000 gas

事件的声明由event关键字开头,然后跟事件名称,括号里面写好事件需要记录的变量类型和变量名。以ERC20代币合约的Transfer事件为例:

event Transfer(address indexed from, address indexed to, uint256 value);

 每个事件最多有3个带indexed的变量,Transfer事件共记录了3个变量fromtovalue,分别对应代币的转账地址,接收地址和转账数量。同时fromto前面带着indexed关键字,表示很重要,程序可以轻松的筛选出特定转账地址和接收地址的转账事件

// 定义_transfer函数,执行转账逻辑
function _transfer(
    address from,
    address to,
    uint256 amount
) external {

    _balances[from] = 10000000; // 给转账地址一些初始代币

    _balances[from] -=  amount; // from地址减去转账数量
    _balances[to] += amount; // to地址加上转账数量

    // 释放事件
    emit Transfer(from, to, amount);
}

2. 继承

继承(inheritance),包括简单继承,多重继承,以及修饰器(modifier)和构造函数(constructor)的继承。

virtual: 父合约中的函数,如果希望子合约重写,需要加上virtual关键字

override:子合约重写了父合约中的函数,需要加上override关键。

简单继承

contract Yeye {
    event Log(string msg);

    // 定义3个function: hip(), pop(), man(),Log值为Yeye。
    function hip() public virtual{
        emit Log("Yeye");
    }

    function pop() public virtual{
        emit Log("Yeye");
    }

    function yeye() public virtual {
        emit Log("Yeye");
    }
}

我们再定义一个合约Baba 

contract Baba is Yeye{
    // 继承两个function: hip()和pop(),输出改为Baba。
    function hip() public virtual override{
        emit Log("Baba");
    }

    function pop() public virtual override{
        emit Log("Baba");
    }

    function baba() public virtual{
        emit Log("Baba");
    }
}

多重继承

  1. 继承时要按辈分最高到最低的顺序排。比如我们写一个Erzi合约,继承Yeye合约和Baba合约,那么就要写成contract Erzi is Yeye, Baba,而不能写成contract Erzi is Baba, Yeye,不然就会报错。
  2. 如果某一个函数在多个继承的合约里都存在,比如例子中的hip()pop(),在子合约里必须重写,不然会报错。
  3. 重写在多个父合约中重名函数时,override关键字后面要加上父合约名字,例如override(Yeye, Baba)
contract Erzi is Yeye, Baba{
    // 继承两个function: hip()和pop(),输出值为Erzi。
    function hip() public virtual override(Yeye, Baba){
        emit Log("Erzi");
    }

    function pop() public virtual override(Yeye, Baba) {
        emit Log("Erzi");
    }

修饰器的继承

Solidity中的修饰器(Modifier)同样可以继承,用法与函数继承类似,在相应的地方加virtualoverride关键字即可。

构造函数的继承

子合约有两种方法继承父合约的构造函数。举个简单的例子,父合约A里面有一个状态变量a,并由构造函数的参数来确定:

// 构造函数的继承
abstract contract A {
    uint public a;

    constructor(uint _a) {
        a = _a;
    }
}
  1. 在继承时声明父构造函数的参数,例如:contract B is A(1)
  2. 在子合约的构造函数中声明构造函数的参数,例如:
contract C is A {
    constructor(uint _c) A(_c * _c) {}
}

调用父合约的函数

子合约有两种方式调用父合约的函数,直接调用和利用super关键字。

  • 直接调用:子合约可以直接用父合约名.函数名()的方式来调用父合约函数,例如Yeye.pop()
    function callParent() public{
        Yeye.pop();
    }
  • super关键字:子合约可以利用super.函数名()来调用最近的父合约函数。solidity继承关系按声明时从右到左的顺序是:contract Erzi is Yeye, Baba,那么Baba是最近的父合约,super.pop()将调用Baba.pop()而不是Yeye.pop()
    function callParentSuper() public{
        // 将调用最近的父合约函数,Baba.pop()
        super.pop();
    }

猜你喜欢

转载自blog.csdn.net/qincheng168/article/details/128071484