Inheritance

Inheritance
Inheritance is a fundamental concept in object-oriented programming, and Solidity supports inheritance in its contracts.
Inheritance allows a contract to inherit properties and behavior from another contract, which can help reduce code duplication and improve code reusability.
In Solidity, a contract can inherit from another contract using the
iskeyword, followed by the name of the base contract. Here's an example:
contract Animal {
string public name;
uint public age;
constructor(string memory _name, uint _age) {
name = _name;
age = _age;
}
function eat() public virtual returns (string memory) {
return "The animal is eating.";
}
}
contract Dog is Animal {
string public breed;
constructor(string memory _name, uint _age, string memory _breed) Animal(_name, _age) {
breed = _breed;
}
function bark() public returns (string memory) {
return "Woof!";
}
function eat() public override returns (string memory) {
return "The dog is eating.";
}
}
In this example, we have two contracts:
AnimalandDog. TheDogcontract inherits from theAnimalcontract using theiskeyword. This means that theDogcontract inherits all the properties and functions of theAnimalcontract, including thenameandageproperties and theeat()function.The
Dogcontract also adds its own property,breed, and its own function,bark(). TheDogcontract overrides theeat()function from theAnimalcontract using theoverridekeyword, which allows theDogcontract to provide its own implementation of theeat()function.With inheritance, the
Dogcontract can use all the properties and functions from theAnimalcontract, as well as its own properties and functions. This can help reduce code duplication and improve code reusability by allowing you to define common properties and functions in a base contract and then inherit from that contract in other contracts.Note that in Solidity, you can also use multiple inheritance, where a contract inherits from multiple base contracts. To do this, you simply list the base contracts separated by commas in the contract declaration. However, be careful when using multiple inheritance, as it can make your code more
Parent Constructor
In Solidity, you can call a parent contract's constructor using the
superkeyword.Here's an example of how to call the parent constructor in a derived contract:
pragma solidity ^0.8.0;
contract Parent {
uint public x;
constructor(uint _x) {
x = _x;
}
}
contract Child is Parent {
uint public y;
constructor(uint _x, uint _y) Parent(_x) {
y = _y;
}
}
In the example above,
Childis a derived contract that inherits fromParent.Childhas its own constructor that takes two arguments:_xand_y.To call the parent constructor with
_x, we useParent(_x)in theChildconstructor. This tells Solidity to execute theParentconstructor with the_xargument passed to theChildconstructor.Note that if the parent contract has a constructor with arguments, the derived contract must provide values for those arguments when calling the parent constructor using
super.
Super Keyword in Solidity
In Solidity,
superis a keyword used to call functions or constructors defined in a parent contract from a child contract that inherits from it.superis used to access functions and state variables defined in the parent contract.It can be used to call functions with the same name in the parent contract or to call the parent constructor from the derived contract constructor.
Here are a few examples of how super can be used in Solidity:
- Calling a function in the parent contract:
csharpCopy codepragma solidity ^0.8.0;
contract Parent {
uint public x;
function foo() public virtual {
x = 1;
}
}
contract Child is Parent {
function foo() public override {
super.foo();
// do something else
}
}
In this example, Child overrides the foo function from Parent. The foo function in Child calls super.foo(), which calls the foo function in Parent and sets x to 1.
- Calling the parent constructor from the derived contract constructor:
pragma solidity ^0.8.0;
contract Parent {
uint public x;
constructor(uint _x) {
x = _x;
}
}
contract Child is Parent {
uint public y;
constructor(uint _x, uint _y) Parent(_x) {
y = _y;
}
}
In this example,
Childcalls the parent constructor usingParent(_x)in its own constructor.This passes the
_xargument to theParentconstructor and initializes thexvariable in theParentcontract. TheChildconstructor then initializes its ownyvariable with the_yargument.Overall,
superis an important keyword in Solidity that allows for inheritance and code reuse in smart contract development.
Method Overriding in Solidity
Method overriding is a feature of object-oriented programming that allows a subclass to provide its own implementation of a method that is already defined in its superclass. In Solidity, method overriding can be used when one contract inherits from another contract.
To override a method in a derived contract, the derived contract must define a function with the same name and function signature as the function in the parent contract.
The
overridekeyword is used to indicate that the derived contract is overriding the parent contract's function.
Here's an example:
pragma solidity ^0.8.0;
contract Parent {
function foo() public virtual {
// parent implementation of foo
}
}
contract Child is Parent {
function foo() public override {
// child implementation of foo
}
}
In this example,
Childoverrides thefoofunction fromParent. Theoverridekeyword is used to indicate thatChildis intentionally overriding thefoofunction fromParent.When a contract calls the
foofunction on an instance ofChild, the implementation inChildwill be executed instead of the implementation inParent.It's important to note that if a contract overrides a function, the function must be marked as
virtualin the parent contract.Otherwise, Solidity will generate a warning. Additionally, if the function is marked as
externalorpublic, it must have the same visibility in the derived contract.
Method Resolution In Solidity
Method Resolution Order (MRO) is the order in which methods are searched for in a class hierarchy. In Solidity, MRO is used to determine which implementation of an overridden function is called when a function is called on an instance of a derived contract.
Solidity uses a linearized MRO, also known as C3 linearization, to determine the order in which methods are searched for in the inheritance hierarchy.
The linearization algorithm ensures that the order preserves the desired properties of inheritance, such as monotonicity and local precedence ordering.
Here's an example:
pragma solidity ^0.8.0;
contract A {
function foo() public virtual returns (string memory) {
return "A";
}
}
contract B is A {
function foo() public virtual override returns (string memory) {
return "B";
}
}
contract C is A {
function foo() public virtual override returns (string memory) {
return "C";
}
}
contract D is B, C {
function foo() public override(B, C) returns (string memory) {
return super.foo();
}
}
- In this example,
Dis a derived contract that inherits fromBandC, which both inherit fromA.Doverrides thefoofunction fromA, andsuper.foo()is used to call the implementation offooin the linearized MRO of the parent contracts (BandC).
The linearization of D is calculated as follows:
L(D) = [D] + merge(L(B), L(C), [B, C])
where merge combines the linearizations of B and C with the B and C themselves, in the order they are provided.
The resulting linearization of
Dis[D, B, C, A], which means that when thefoofunction is called on an instance ofD, it will first look for the implementation inD, then inB, then inC, and finally inA. If the function is not found in any of those contracts, a runtime error will occur.By using a linearized MRO, Solidity ensures that the correct implementation of an overridden function is called, even in complex inheritance hierarchies.
Method Overloading
Method overloading is a feature of object-oriented programming that allows a class to have multiple methods with the same name but different parameter lists. In Solidity, method overloading can be used to provide multiple functions with the same name that perform different operations based on the input parameters.
Solidity supports method overloading by allowing functions to have the same name, but with different parameter lists. The functions must differ in the number or types of their parameters.
Here's an example:
pragma solidity ^0.8.0;
contract Overloading {
function foo(uint256 x) public pure returns (uint256) {
return x * 2;
}
function foo(string memory s) public pure returns (string memory) {
return s;
}
}
In this example, the
Overloadingcontract defines two functions namedfoo, one that takes auint256parameter and returns auint256value, and another that takes astringparameter and returns astringvalue.When a contract calls the
foofunction on an instance ofOverloading, Solidity will determine which function to call based on the number and types of the input parameters.
For example:
Overloading o = new Overloading();
uint256 x = 42;
string memory s = "hello";
uint256 result1 = o.foo(x); // calls foo(uint256)
string memory result2 = o.foo(s); // calls foo(string)
In this example, the first call to
foowith auint256parameter will call the firstfoofunction inOverloading, while the second call tofoowith astringparameter will call the secondfoofunction.t's important to note that while Solidity allows method overloading, it does not support method overriding with the same function signature. If two functions in a contract have the same name and function signature, a compile-time error will occur.



