導入
あるコントラクトの機能を別のコントラクトが引き継いで拡張するのが 継承(inheritance) です。「所有者だけが操作できる」といった定番機能を毎回書かず、共通の親から受け継ぎます。
説明
is キーワードで親コントラクトを継承します。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// 親:所有者の管理機能
contract Ownable {
address public owner;
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner, "owner only");
_;
}
}
// 子:Ownable を継承して機能を足す
contract Shop is Ownable {
uint256 public price;
// 親の onlyOwner をそのまま使える
function setPrice(uint256 _price) public onlyOwner {
price = _price;
}
}
contract Shop is Ownable…ShopはOwnableを継承。親のowner/onlyOwnerを自分のもののように使える。- 親の
internal/publicなメンバーは子から使えるが、privateは使えない(第2章の可視性表を参照)。 - 親の関数を子で上書きするときは
virtual(親側)とoverride(子側)を付ける。
graph TB
O["Ownable(親)<br/>owner / onlyOwner"]
O --> S["Shop(子)<br/>is Ownable<br/>price / setPrice"]
O --> T["Token(別の子)<br/>is Ownable"]
実務では、監査済みの安全な実装を集めた OpenZeppelin というライブラリの Ownable などを継承するのが定番です。「車輪の再発明」をせず、実績あるコードを継承して土台にします。
やってみよう
Ownable を一度きちんと作れば、Shop でも Token でも is Ownable するだけで所有者管理が手に入ります。共通機能を親にまとめる設計が、コードの重複とバグを同時に減らすことを実感してみましょう。