100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Inheritance in Solidity

Inheritance lets contracts reuse and extend each other with the is keyword, virtual/override, super, C3-linearized multiple inheritance, and ordered constructor chaining.

Storage & Data StructuresIntermediate10 min readJul 10, 2026
Analogies

Reusing Code with Inheritance

Inheritance lets one contract build on another, reusing its logic instead of duplicating it. A derived contract declares contract Child is Parent, and immediately gains the parent's non-private state variables and functions. This underpins nearly every real-world Solidity project — access-control mixins like Ownable, token bases like ERC20, and reentrancy guards are all inherited. Inheritance keeps contracts DRY and lets audited base contracts, such as OpenZeppelin's, provide battle-tested behavior you extend rather than reimplement.

🏏

Cricket analogy: Inheritance is like an academy player inheriting the club's training drills and kit, then adding their own shots — a derived contract gets the base's functions plus its own.

virtual, override, and super

To let a derived contract replace a function, the base must mark it virtual, and the derived version must be marked override. Inside the override you can call the parent's implementation with super.functionName(...), which invokes the next contract in the inheritance chain rather than any one specific parent. This is how you wrap base behavior — for example, adding a zero-address check before delegating to super.transferOwnership(to). A function that is itself overridden further down the chain must be both override and virtual.

🏏

Cricket analogy: A base method marked virtual is like a coaching drill flagged 'customizable' — a player can override it with their own technique, and super lets them still run the original drill first.

solidity
contract Ownable {
    address public owner = msg.sender;

    function transferOwnership(address to) public virtual {
        owner = to;
    }
}

contract Restricted is Ownable {
    function transferOwnership(address to) public override {
        require(to != address(0), "zero address");
        super.transferOwnership(to); // run the parent implementation
    }
}

Only functions marked virtual can be overridden, and state variables can never be overridden. A public state variable auto-generates a getter, but to change behavior a derived contract must override an explicit function, not the variable itself.

Multiple Inheritance and C3 Linearization

Solidity supports inheriting from several contracts at once, and resolves the resulting graph using C3 linearization — the same algorithm Python uses. You must list base contracts from most-base to most-derived, and the linearization determines the order in which overrides and super calls are dispatched. When two parents define the same function, the override must name all of them, as in override(A, B). This deterministic ordering is how Solidity tames the classic 'diamond problem' of multiple inheritance.

🏏

Cricket analogy: Multiple inheritance is a player learning from both a batting coach and a fielding coach; C3 linearization fixes a strict order so overlapping advice resolves predictably, most-base coach last.

In multiple inheritance, listing base contracts in the wrong order breaks C3 linearization and fails to compile. When two parents define the same function, the override must explicitly name every base it overrides, e.g. override(A, B), or the compiler rejects it.

Constructor Chaining

When a contract is deployed, base constructors run before the derived constructor, in linearization order, so a contract is never used before its foundations are set up. You pass arguments to a base constructor either in the inheritance list (contract C is Base(1)) or, when the value is computed, in the derived constructor's modifier list (constructor(uint x) Base(x * 2) {}). Getting this chain right ensures every inherited state variable is initialized exactly once, in a predictable sequence, before the contract goes live.

🏏

Cricket analogy: Constructor chaining is like a new signing being kitted out by the academy before the senior team adds their gear — base constructors run first, in linearization order, then the derived one.

solidity
contract A {
    constructor(uint n) { /* init A */ }
}

contract B {
    constructor(uint n) { /* init B */ }
}

// Bases run in linearization order, not the order of arguments
contract C is A, B {
    constructor() A(1) B(2) {}
}
  • A contract inherits another with the is keyword, gaining its non-private functions and state variables.
  • A base function must be marked virtual to be overridable, and the overriding function must use override.
  • super calls the next implementation in the C3-linearized inheritance chain, not one fixed parent.
  • Solidity supports multiple inheritance and resolves it with C3 linearization; bases are listed most-base first.
  • An override that replaces several parents must name them all, e.g. override(A, B).
  • Base constructors execute before the derived constructor, in linearization order, receiving arguments via the inheritance or modifier list.
  • State variables cannot be overridden, and private functions are not visible to derived contracts.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#SolidityStudyNotes#InheritanceInSolidity#Inheritance#Solidity#Reusing#Code#OOP#StudyNotes#SkillVeris