virtual 키워드
부모 컨트랙트의 함수를 자식이 재정의(override) 할 수 있게 하려면, 그 함수에 virtual 키워드를 붙여야 합니다. virtual 은 "이 함수는 자식이 바꿀 수 있다" 는 허락의 표시입니다. 반대로 virtual 이 없는 함수는 자식이 같은 이름으로 다시 정의할 수 없으며, 시도하면 컴파일 오류가 납니다. Solidity 가 이렇게 명시적인 허락을 요구하는 이유는, 의도하지 않은 재정의가 보안 사고로 이어지지 않게 하기 위해서입니다.
contract Base {
// 이 함수는 자식이 재정의할 수 있습니다.
function greet() public pure virtual returns (string memory) {
return "Hello from Base";
}
}virtual 을 빼면 자식 컨트랙트에서 같은 이름의 함수를 재정의하려 할 때 컴파일 오류가 납니다.
재정의를 허용하려면 반드시 부모 함수에 virtual 을 붙이세요.
재정의 가능성을 열어두는 설계
virtual 은 문법이기 이전에 설계 의도 를 드러내는 표시입니다. 여기는 자식이 자유롭게 바꿔도 되는 확장 지점이라고 코드로 밝혀 두는 것입니다. 그래서 모든 함수에 습관적으로 virtual 을 붙이는 건 좋지 않습니다. 핵심 보안 로직처럼 자식이 함부로 바꾸면 안 되는 함수는 virtual 없이 두어 재정의 자체를 막는 편이 안전합니다.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Payment {
// 수수료 정책은 자식이 바꿀 수 있도록 virtual 로 열어둔다.
function fee() public pure virtual returns (uint256) {
return 100;
}
}virtual 과 override 의 짝
virtual 은 혼자 쓰이지 않습니다. 부모가 virtual 로 문을 열어주면, 자식은 override 키워드로 그 함수를 다시 구현합니다. 즉 부모의 virtual 과 자식의 override 는 항상 한 쌍 으로 동작합니다.
virtual = "재정의해도 된다(부모 쪽 선언)", override = "재정의한다(자식 쪽 선언)". 다음
강의에서 override 를 자세히 다룹니다.