본문 바로가기
etc/블록체인 뉴딜일자리사업

솔리디티 기초: 예외처리, 상속, 오버라이드

by vellahw 2023. 5. 23.

 

💭 서론

교육 15일차

오늘도 어제와 같이 솔리디티 기초 수업을 들었다. 코딩을 해봤어도 역시 언어가 다르고 문법이 다르니 아직도 조금 헤맸지만 점점 개념이 잡히고 있다. 가시성 지정자랑 모디파이어 정의하는 위치 같은게 헷갈린다. ㅎ

 

 

 

✔️ 조건문과 반복문

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract Ex4_3 {
   
    function fun1(uint a) public pure returns(uint) {
        if(a>=1){
            a = 1;
        }else if(a>=2){
            a = 2;    
        }else if(a>=3){
            a = 3;    
        }else{
            a = 4;
        }
        return a;
    }

    function fun2(uint a) public pure returns(uint) {
        if(a>=1){
            a = 1;
        }
        if(a>=2){
            a = 2;
        }
        if(a>=3){
            a = 3;
        }else{
            a = 4;
        }
        return a;
    }

}

(코드 출처)

 

위 코드 속 fun1() 함수와 fun2() 함수 중 어떤 것이 실행 속도가 더 빠를까?

답은 fun1()이다.

fun1()은 if-else문으로 작성되었고 하나의 if문에 조건이 걸리면 뒤 로직은 실행되지 않고 조건문을 빠져나간다.

반면 fun2()는 조건문에 빠져나가는 것 없이 if문 하나하나가 다 동작되기 때문에 fun1()의 실행 속도가 더 빠른 것.

 

 

 

✔️ 솔리디티 예외처리

솔리디티엔 예외를 처리하는 3가지 함수가 있다.

 

1. revert("에러메세지")

특정한 조건 없이 revert() 함수를 마주치면 예외를 즉시 발생시키며, 이전까지 로직이 실행되면서 사용된 가스비를 돌려준다.

괄호안엔 에러메세지로 출력시킬 문자열을 입력한다.

 

// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8;

contract revertTest {  
  function test() public pure {
      revert("error");
  }
}

배포 후 test() 함수를 실행시키면 트랜잭션이 초기로 돌아갔다는 메세지와 직접 입력한 에러메세지가 출력된다.

 

2. require(조건, "에러메세지")

특정 조건에 부합하지 않으면 예외를 발생시킨다.revert와 같이 가스비를 돌려주며,

일반적으로 입력 파라미터 또는 출력값의 유효성을 검사하는데 주로 사용된다.

괄호안에 조건과 에러메세지를 입력하면 되는데, 에러메세지는 생략 가능하다.

// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8;

contract requireTest{
	bool test = false;
  function fnTest() public view{
      require(test, "require error!");
  }
}

위 코드에서 bool 자료형 test의 값을 False를 줘서 fnTest() 함수를 실행시키면 에러가 발생한다.

 

에러메세지도 출력됨

 

3. assert(bool condition)

특정 조건에 부합하지 않으면 예외를 발생시키며 가스비를 돌려주지 않고 모두 소진한다.

실행의 특정 단계에서 항상 참이어야 하는 논리적 주장을 확인한다.

 

 

 

✔️ 객체 지향을 이해하기

💡 생성자 constructor

생성자는 스마트 컨트랙트가 생성 또는 배포, 인스턴스화 될때 초기값을 설정해주는 용도로 사용된다.

솔리디티 버전에 따라 생성자를 정의하는 방법이 조금 다르다.

 

// 솔리디티 0.7 미만
constructor( ) public {
}

// 솔리디티 0.7 이상
constructor( ){
}

 

💡 인스턴스화

A 컨트랙트에서 B 컨트랙트 가져다 쓰는 것

contract A {
    B instance = new B();
}

contract B {
}

인스턴스화 하기 위해서는 위처럼 정의한다.

 

* 위의 instance는 이름(별명)이다.

B 컨트랙트에서 메서드 등을 가져다 쓰려면 정의해준 이름(별명)을 가지고 instance.메서드명(); 이런식으로 가져오면 된다.

 

 

 

✔️ 상속

👀 상속의 장점

  • 기존에 정의해둔 클래스의 기능을 그대로 물려받을 수 있다.
  • 코드를 재사용할 수 있게된다.

 

솔리디티에서 상속하는 방법

// SPDX-License-Identifier:GPL-30
pragma solidity >= 0.7.0 < 0.9.0;

contract Parent{
    string public familyName = "Kim";
	
    function getFamilyName() view public returns(string memory){
        return familyName;
    } 
}

contract Child is Parent{
    
}

 

솔리디티에서 상속의 형태는 위와 같이 상속받을 컨트랙트 is 상속해줄 컨트랙트 이다.
Child 컨트랙트는 Parent 컨트랙트를 상속받았기 때문에 Parent 컨트랙트의 변수와 상수 모두를 사용할 수 있다.

 

 

 

✔️ 솔리디티는 오버라이딩이 불가능?

우선, 상속에는 섀도잉 개념이 있다. 상속에서 부모클래스에 사용된 변수를 자식클래스에서 동일하게 사용될때, 이를 섀도잉이라고 한다. 

솔리디티에서는 섀도잉 기법이 적용이 되지 않는데, 예제와 함께 살펴보자.

 

// SPDX-License-Identifier:GPL-30
pragma solidity >= 0.7.0 < 0.9.0;

contract Parent{
    string public familyName = "Kim";
	
    function getFamilyName() view public returns(string memory){
        return familyName;
    } 
}

// 불가능
//contract Child is Parent{
//    string public familyName = "Park";
//}

 

주석 처리한 Child 컨트랙트의 재선언 방법으로 오버라이딩 할 수 없다는 뜻이다.

상속받은 상태변수를 오버라이딩 하기 위해서는 아래와 같이 생성자로 다시 생성해야만한다.

 

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

contract Parent {
    string public familyName = "A";

    function getFamilyName() public view returns (string memory) {
        return familyName;
    }
}

// 올바른 방법
contract Child is Parent {
    constructor() {
        familyName = "B";
    }
}

 

 

 

✔️ 오버라이딩

method override (메서드 오버라이드, 오버라이딩)

메서드 오버라이딩(Method Overriding)이란, 여러 클래스에 걸쳐서 같은 이름의 메서드를 만드는 것이다.

예를 들어 부모 클래스, 전사⚔️ 캐릭터 클래스, 마법사🔮 캐릭터 클래스에 공통으로 attack이라는 메서드가 있지만, 각각 하는 일이 다를 때 같은 이름의 메서드를 클래스별로 구현하면 된다. 이렇게 되면 부모 클래스에서 만든 메서드를 자식 클래스에서는 변경해서 사용한다. 

 

예제를 통해 오버라이딩 체험(?)하기

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

contract Parent {
    uint256 public money = 100; 

    //오버라이딩 당할(?) 함수 'virtual'
    function getMoney() view public virtual returns (uint256) {
        return money;
    }
}

contract Child is Parent {
    uint256 public earning = 100;
    
    // 오버라이드 'override'
    function getMoney() view public override returns(uint256){
        return money + earning;
    }
}

 

컨트랙트 Parent의 getMoney() 함수를 보면 virtual 이란게 쓰여있다.

자식 컨트랙에서 오버라이딩 하기 위해선 부모 컨트랙트에서 virtual 을 사용해 오버라이딩을 할 것이다 라고 표시해주어야 한다.

 

자식 컨트랙트에서는 override 를 붙여주면 오버라이드 해서 수정할 수 있다.

Parent 컨트랙트를 상속한 Child 컨트랙트에서 getMoney 함수를 오버라이딩 해주었다.

 

 

 

👀 ERC20 import, 상속 해보기

ERC20 깃헙 페이지에 들어가보면 상단에 파일들을 import 해서 사용중인 것을 알 수 있다.

깃허브 링크 자체를 긁어와? import해서 사용할 수 있다.

 

import 해서 상속하기

 

 


참고

댓글