Track 4 · Solidity foundations · lesson 13
Inheritance
10 min
Track 4 · Solidity foundations · lesson 13
10 min
You have written the same owner-and-modifier block three times now. Inheritance is how you stop.
contract Store is Ownable { ... }
A child gets the parent's state variables, functions, modifiers and errors, and the parent's constructor runs first.
Notice Store never declared owner, never wrote a constructor, and still ends
up owned by whoever deployed it. All of that came from Ownable.
Inheritance in Solidity is flattened at compile time. There is no runtime delegation and no separate parent object — the compiler produces a single contract containing everything, deployed at a single address.
That matters for storage. Parent state variables occupy slots before the child's, and getting that order wrong is what breaks upgradeable proxies, a track 7 topic.
A parent function can only be replaced if it opts in:
contract Ownable {
function transferOwnership(address to) public virtual onlyOwner { ... }
}
contract Store is Ownable {
function transferOwnership(address to) public override onlyOwner { ... }
}
virtual means "this may be replaced". override means "this replaces
something". Solidity requires both, so an accidental override cannot compile.
Predict
contract Token is ERC20, Ownable, Pausable { ... }
Solidity linearises parents right to left: the rightmost is the most base, the leftmost the most derived. Get the order wrong and you can end up with a different function than you intended, or a compile error about linearisation.
The convention is to list them from most base-like to most derived, which is what OpenZeppelin does throughout.
Check