Solidity / Өвлөлт (inheritance)

Өвлөлт (inheritance)

Өвлөлт нь нэг contract-ын код, функц, state-ийг нөгөөд дамжуулах механизм юм. Кодын давхардлыг багасгаж, дахин ашиглалтыг нэмэгдүүлнэ.

is — өвлөх

is түлхүүр үгээр нэг contract нөгөөгөөсөө өвлөнэ.

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Эцэг contract
contract Animal {
    string public name;

    constructor(string memory _name) {
        name = _name;
    }

    function speak() public pure virtual returns (string memory) {
        return "...";
    }
}

// Хүү contract — Animal-аас өвлөнэ
contract Dog is Animal {
    constructor(string memory _name) Animal(_name) {}

    function speak() public pure override returns (string memory) {
        return "Хав хав!";
    }
}

Dog contract нь Animal-ын name state variable болон constructor-ыг өвлөнө.

virtual ба override

  • virtual — эцэг contract-д: энэ функцийг хүүд дахин тодорхойлж болно гэсэн утга
  • override — хүү contract-д: эцгийн функцийг дахин тодорхойлж байна гэсэн утга
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Shape {
    function area() public pure virtual returns (uint256) {
        return 0;
    }
}

contract Square is Shape {
    uint256 public side;

    constructor(uint256 _side) {
        side = _side;
    }

    function area() public view override returns (uint256) {
        return side * side;
    }
}

contract Circle is Shape {
    uint256 public radius;

    constructor(uint256 _radius) {
        radius = _radius;
    }

    // π ≈ 314, хялбарчилсан тооцоо
    function area() public view override returns (uint256) {
        return (314 * radius * radius) / 100;
    }
}

super — эцгийн функцийг дуудах

super түлхүүр үгээр эцгийн функцийг хүүгийн дотроос дуудаж болно.

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Ownable {
    address public owner;

    constructor() {
        owner = msg.sender;
    }

    function transferOwnership(address newOwner) public virtual {
        require(newOwner != address(0), "Хүчингүй хаяг");
        owner = newOwner;
    }
}

contract SecureOwnable is Ownable {
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    function transferOwnership(address newOwner) public override {
        emit OwnershipTransferred(owner, newOwner);
        super.transferOwnership(newOwner); // Эцгийн функцийг дуудна
    }
}

Олон өвлөлт (multiple inheritance)

Solidity нь олон contract-аас зэрэг өвлөх боломжтой. Солилцооны дараалал нь C3 linearization алгоритмаар тодорхойлогдоно.

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract A {
    function greet() public pure virtual returns (string memory) {
        return "A";
    }
}

contract B is A {
    function greet() public pure virtual override returns (string memory) {
        return "B";
    }
}

contract C is A {
    function greet() public pure virtual override returns (string memory) {
        return "C";
    }
}

// B, C хоёроос өвлөхдөө override(B, C) хэлбэрээр бичнэ
contract D is B, C {
    function greet() public pure override(B, C) returns (string memory) {
        return super.greet(); // C-ийн greet()-г дуудна (хамгийн сүүлийн эцэг)
    }
}

Олон өвлөлтийн үед is дараах эцгүүдийг баруун тийш нь хамгийн ерөнхий нь байхаар жагсаана.

Практик жишээ — Ownable + Pausable

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Ownable {
    address public owner;

    modifier onlyOwner() {
        require(msg.sender == owner, "Зөвхөн эзэмшигч");
        _;
    }

    constructor() {
        owner = msg.sender;
    }
}

contract Pausable is Ownable {
    bool public paused;

    modifier whenNotPaused() {
        require(!paused, "Contract түр зогсоогдсон");
        _;
    }

    function pause() public onlyOwner {
        paused = true;
    }

    function unpause() public onlyOwner {
        paused = false;
    }
}

contract Token is Pausable {
    mapping(address => uint256) public balances;

    function transfer(address to, uint256 amount) public whenNotPaused {
        require(balances[msg.sender] >= amount, "Үлдэгдэл хүрэлцэхгүй");
        balances[msg.sender] -= amount;
        balances[to] += amount;
    }
}

Token нь Pausable-аас, Pausable нь Ownable-аас өвлөж гинжин байдлаар бүх функц, modifier-ийг дамжуулна.

Дараагийн хичээлд:

Interface ашиглан contract хоорондын харилцааг стандартчилах аргыг судална.