추상 컨트랙트 (abstract)
추상 컨트랙트(abstract contract) 는 인터페이스와 일반 컨트랙트의 중간에 있는 개념입니다.
일부 함수는 구현하고, 일부 함수는 구현하지 않은 채로 남겨둘 수 있습니다. 즉 "공통으로 쓸 코드는
미리 채워주고, 나머지 빈칸은 자식에게 맡기는" 반쯤 완성된 설계도입니다.
구현되지 않은 함수가 하나라도 있으면 그 컨트랙트는 반드시 abstract 로 선언해야 합니다. 추상
컨트랙트는 단독으로 배포할 수 없고, 상속받아 나머지를 완성한 컨트랙트만 배포할 수 있습니다.
인터페이스와 다른 점
인터페이스가 "껍데기 약속"만 담는다면, 추상 컨트랙트는 그보다 훨씬 자유롭습니다.
- 함수
구현을 가질 수 있다. 일부만 비워두어도 된다. - 상태 변수를 둘 수 있다.
생성자(constructor)도 정의할 수 있다.- 함수 가시성은
public·internal등 원하는 대로 쓴다.
미구현 함수에는 virtual 키워드를 붙여 "자식이 채워야 한다"는 것을 표시합니다.
virtual과 override의 짝
부모의 미구현(또는 재정의 가능) 함수에는 virtual, 자식이 채우는 함수에는 override 를 붙입니다.
이 둘이 짝을 이뤄 안전한 다형성 을 만듭니다.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// 구현하지 않은 함수가 있으므로 abstract 로 선언한다.
abstract contract Animal {
string public species;
constructor(string memory _species) {
species = _species;
}
// 구현 있음: 공통 동작
function describe() public view returns (string memory) {
return species;
}
// 구현 없음: 자식이 채워야 함 (virtual)
function sound() public view virtual returns (string memory);
}
// 추상 컨트랙트를 상속해 나머지를 완성하면 배포할 수 있다.
contract Dog is Animal {
constructor() Animal("Dog") {}
function sound() public pure override returns (string memory) {
return "Woof";
}
}여러 컨트랙트가 공통 상태와 공통 로직을 공유하면서 일부 동작만 다르게 해야 할 때 추상 컨트랙트가 최적입니다. OpenZeppelin 의 많은 기반 컨트랙트가 이 방식으로 설계되어 있습니다.