区块链开发之Solidity编程基础(五)合约继承、抽象合约、接口


本文主要讲解下Solidity的继承系统,主要内容为 单继承以及 多重继承。如果有其他编程经验的话,便知道继承的主要目的在于优化重复代码,是面向对象编程思想的体现。

原理

solidity通过复制包括多态的代码来支持多重继承,即当一个合约从多个合约继承时,在区块链上只有一个合约被创建,所有基类合约的代码被复制到创建的合约中

所有的函数调用都是虚拟的,这意味着最远的派生函数会被调用,除非明确给出合约名称。派生的合约需要提供所有父合约需要的所有参数。

单继承

pragma solidity ^0.4.0;
contract Base {
    
    
	uint _x;
	// Base基类构造函数携带参数
	function Base(uint x) {
    
    
		_x = x;
	}
}

// 使用 is 从另一个合约派生。派生合约可以访问所有非私有成员,包括内部函数和状态变量,
// 但无法通过 this 来外部访问。
contract Derived is Base(7) {
    
    
	function Derived(uint y) Base(y * y) {
    
    
	}
}

派生合约需要提供基类构造函数需要的所有参数,可以采用两种方式来实例化。
1、使用 is Base(7)携带默认参数方式
2、派生类指定基类构造参数时,在派生类的构造函数定义Base(y * y)的方式

优先使用第二种方式,灵活指定参数。

多重继承

同名修饰器或函数、事件

在多重继承中,基类合约的次序是非常重要的,当一个合约从多个其他合约那里继承,在区块链上仅会创建一个合约,通过复制父合约里的代码来形成继承合约。当继承最终导致一个合约同时存在多个相同名字的修饰器或函数,那将会提示错误。当事件和修饰器同名,或者函数和事件同名时,同样会被认为是一个错误。

菱形继承问题

多重继承在很多编程语言里,要解决的一个问题是,菱形继承问题,又称钻石问题
对于基类在 is 后面的顺序很重要。 在下面的代码中,Solidity 会给出“ Linearization of inheritance graph impossible ”这样的错误。

pragma solidity ^0.4.0;

contract X {
    
    }
contract A is X {
    
    }
contract C is A, X {
    
    }

代码编译出错的原因是 C 要求 X 重写 A (因为定义的顺序是 A, X ), 但是 A 本身要求重写 X,无法解决这种冲突。

多重继承的函数调用

pragma solidity ^0.4.0;

contract owned {
    
    
    function owned() public {
    
     owner = msg.sender; }
    address owner;
}

contract mortal is owned {
    
    
    function kill() public {
    
    
        if (msg.sender == owner) selfdestruct(owner);
    }
}

contract Base1 is mortal {
    
    
    function kill() public {
    
     /* 清除操作 1 */ super.kill(); }
}


contract Base2 is mortal {
    
    
    function kill() public {
    
     /* 清除操作 2 */ super.kill(); }
}

contract Final is Base1, Base2 {
    
    
}

以上的继承序列是:Final, Base2, Base1, mortal, ownerd。

Base1和Base2 都继承mortal,如果Base1和Base2的kill函数不添加super关键字时,调用Final.kill()只会调用Base2.kill(),而不知道Base1的kill函数。当加入super关键字时,base2会再调用继承序列里的下一个base1里的kill,这样便不会漏过业务逻辑的执行。

抽象合约

抽象合约的函数可以缺少实现,用于描述合约,并用于继承

pragma solidity ^0.4.0;

contract Feline {
    
    
    function utterance() public returns (bytes32);
}

如果合约继承自抽象合约,并且没有通过重写来实现所有未实现的函数,那么它本身就是抽象的。

pragma solidity ^0.4.0;

contract Feline {
    
    
    function utterance() public returns (bytes32);
}

contract Cat is Feline {
    
    
    function utterance() public returns (bytes32) {
    
     return "miaow"; }
}

接口

接口类似于抽象合约,但是它们不能实现任何函数。还有进一步的限制:

  1. 无法继承其他合约或接口。
  2. 无法定义构造函数。
  3. 无法定义变量。
  4. 无法定义结构体
  5. 无法定义枚举。

接口基本上仅限于合约 ABI 可以表示的内容,并且 ABI 和接口之间的转换应该不会丢失任何信息。

接口interface关键字表示:

pragma solidity ^0.4.11;

interface Token {
    
    
    function transfer(address recipient, uint amount) public;
}

就像继承其他合约一样,合约可以继承接口。

猜你喜欢

转载自blog.csdn.net/BBinChina/article/details/123619336