Inheritance and abstract contracts

Compose contracts from reusable base contracts — the way OpenZeppelin was designed to be used.

Basic inheritance

Solidity supports single and multiple inheritance using the is keyword. Derived contracts inherit all public and internal state variables, functions, and modifiers from their parents.

solidity
contract Ownable {
    address public owner;

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, 'Not owner');
        _;
    }

    function transferOwnership(address newOwner) public onlyOwner {
        owner = newOwner;
    }
}

contract MyToken is Ownable {
    mapping(address => uint256) public balances;

    function adminMint(address to, uint256 amount) external onlyOwner {
        // onlyOwner from Ownable is available here
        balances[to] += amount;
    }
}

Multiple inheritance

Solidity resolves multiple inheritance using C3 linearization. List parents from most-base to most-derived.

solidity
contract MyContract is Ownable, Pausable, ReentrancyGuard {
    function sensitiveAction() external onlyOwner whenNotPaused nonReentrant {
        // uses modifiers from all three parents
    }
}

Abstract contracts

An abstract contract has at least one function without an implementation. It cannot be deployed on its own — it must be inherited and its abstract functions implemented by a concrete contract.

solidity
abstract contract BaseToken {
    mapping(address => uint256) internal _balances;
    uint256 internal _totalSupply;

    // Must be implemented by the derived contract
    function decimals() public pure virtual returns (uint8);

    // Shared implementation available to all derived contracts
    function totalSupply() public view returns (uint256) {
        return _totalSupply;
    }
}

contract USDC is BaseToken {
    function decimals() public pure override returns (uint8) {
        return 6;
    }
}

contract WETH is BaseToken {
    function decimals() public pure override returns (uint8) {
        return 18;
    }
}

virtual and override

Functions that can be overridden must be marked virtual. Functions that override a parent must use override.

solidity
contract Base {
    function greet() public virtual returns (string memory) {
        return 'Hello from Base';
    }
}

contract Derived is Base {
    function greet() public override returns (string memory) {
        return 'Hello from Derived';
    }
}

Calling parent functions with super

solidity
contract Derived is Base {
    function greet() public override returns (string memory) {
        string memory parentGreeting = super.greet();
        return string(abi.encodePacked(parentGreeting, ' and Derived'));
    }
}
←   ModifiersInterfaces   →