본문 바로가기
블록체인교육/솔리디티

[솔리디티] 9. 상속 섀도잉, super키워드, 함수 속성들

by Danny_Kim 2022. 6. 12.

 

[NEW] 누구나 쉽게 따라하는 솔리디티 강의(솔리디티 버전 0.8.13)

1. Helloworld, 카운터컨트랙트, 데이터타입

2. 변수, 상수, 불변, 상태변수 읽고 쓰기

3. 이더 단위, 가스와 가스가격

4. 조건문, 반복문, 맵핑(mapping)

5. 배열, 열거형(enum), 구조체(calldata,memory) 

6. 데이터 저장공간, 함수(view,pure 속성)

7. 에러(error), 함수수정자(modifier)

8. 이벤트(events), 생성자(constructor), 상속

9. 상속, 섀도잉,super키워드 함수 속성들

10. 인터페이스(interface), payable, 이더전송,받기 관련

11. Fallback, Call, Delegate(솔리디티 업그레이드 기법)

12. 함수 선택자(function selector), 다른 컨트랙트 사용 및 생성기법

13. Try Catch, Import(임포트), Library(라이브러리)

14. ABI 디코드, hash 함수, 서명검증, 가스최적화

* 블록체인 전문가들도 놓치기 쉬운 비트코인, 이더리움의 핵심가치 강의

 

블록체인 전문가들도 놓치기 쉬운 비트코인, 이더리움의 핵심 가치 - 인프런 | 강의

블록체인 기획자,개발자,회사 대표라면 반드시 한번은 봐야 하는 강의입니다. 따로 공부할 시간이 없었다면, 이 요약본 강의를 통해서 비트코인,이더리움 백서의 핵심을 이해할 수 있습니다., -

www.inflearn.com

 

 

1. 상속된 상태변수의 섀도잉(shadowing)

 - 상속에서 섀도잉(shadowing) 개념이 있습니다.

 - 변수 섀도잉은, 특정 범위 내에서 선언된 변수가 외부 범위에서 선언된 변수와 같은 이름을 가질 때 발생합니다.

 - 일반적으로 상속에서 섀도잉을 사용하면, 자식 클래스에서 사용된 재정의 요소가 원래 요소를 숨기게 되는 효과가 발생합니다.

 - 즉, 상속에서 부모클래스에 사용된 변수를 자식클래스에서 동일하게 사용될때 이를 섀도잉이라고 합니다. 

 - 솔리디티에서는 이 섀도잉 기법이 적용이 되지 않습니다. 예제를 통해서 살펴보겠습니다.

 - 아래 예제에서, 상태변수는 자식 컨트랙트에서 재선언(re-declaring)에 의한 오버라이딩(overriding)이 안됩니다.

 - A 컨트랙트을 상속받은 B에서, A의 변수 name을 사용하기 위해서 주석처리된 내용처럼 작성하면 오류가 발생합니다.

 - 상속받은 상태변수를 오버라이딩하기 위해서는 아래 두번째 예와 같이 생성자로 다시금 생성해주면 됩니다.

 소스파일

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

contract A {
    string public name = "Contract A";

    function getName() public view returns (string memory) {
        return name;
    }
}

// Shadowing is disallowed in Solidity 0.6
// This will not compile
// contract B is A {
//     string public name = "Contract B";
// }

contract C is A {
    // This is the correct way to override inherited state variables.
    constructor() {
        name = "Contract C";
    }

    // C.getName returns "Contract C"
}

 

2. 부모 컨트랙트 호출 및 super키워드

 - 부모 컨트랙트를 직접적으로 호출하기 위해서는 super 키워드를 사용할 수 있음

 - super 키워드를 사용하면, 상위 부모 컨트랙트를 동일하게 사용할 수 있음

 

 - 상속예제는 아래와 같다.  컨트랙트 A의 함수 foo()와  bar()는 string message를 이벤트 로그로 남긴다.

 - 그리고 B,C는 A를 상속하고, D는 B,C를 상속한다.

 

- B 컨트랙트가 A를 상속받아서 A.foo(), super.bar()를 하는 경우,

- foo()함수를 호출하면, B 컨트랙트의 log()가 호출 된 이후, A 컨트랙트의 foo() 가 호출된다.

- bar()함수를 호출하면, B컨트랙트의 bar()가 호출되고, super키워드에 의해서 A 컨트랙트의 bar() 함수가 호출됨.

- C 컨트랙트가 A를 상속받아서 A.foo(), super.bar()를 하는 경우,

  (결과는 B와 동일하다. 컴파일 후 결과를 확인해보자!)

- 마지막으로 B,C를 상속한 D 컨트랙트의 경우를 살펴보자.

- D 컨트랙트의 Foo() 함수를 호출해보면, D가 A,B,C를 상속받았지만, C컨트랙트만 호출한걸 알 수 있다.

  (컨트랙트 C에 있는 foo() 함수만 호출하였다, C 컨트랙트의 foo() 함수가 super 키워드가 아닌 A.foo()로 상속하였기 때문에)

- 두번째 D컨트랙트의 bar() 함수의 경우, C, B, A를 차례대로 호출하는걸 확인할 수 있다.

- super 키워드로 상속받은 C 컨트랙트의 bar() 함수도 super 키워드 사용, B 컨트랙트의 bar() 함수도 super 키워드 사용했기 때문에

 

전체소스

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

/* Inheritance tree
   A
 /  \
B   C
 \ /
  D
*/

contract A {
    // This is called an event. You can emit events from your function
    // and they are logged into the transaction log.
    // In our case, this will be useful for tracing function calls.
    event Log(string message);

    function foo() public virtual {
        emit Log("A.foo called");
    }

    function bar() public virtual {
        emit Log("A.bar called");
    }
}

contract B is A {
    function foo() public virtual override {
        emit Log("B.foo called");
        A.foo();
    }

    function bar() public virtual override {
        emit Log("B.bar called");
        super.bar();
    }
}

contract C is A {
    function foo() public virtual override {
        emit Log("C.foo called");
        A.foo();
    }

    function bar() public virtual override {
        emit Log("C.bar called");
        super.bar();
    }
}

contract D is B, C {
    // Try:
    // - Call D.foo and check the transaction logs.
    //   Although D inherits A, B and C, it only called C and then A.
    // - Call D.bar and check the transaction logs
    //   D called C, then B, and finally A.
    //   Although super was called twice (by B and C) it only called A once.

    function foo() public override(B, C) {
        super.foo();
    }

    function bar() public override(B, C) {
        super.bar();
    }
}

 

 

3. 함수 속성

 - 솔리디티 함수 속성들.

 - public :  모든 컨트랙트 및 계정에서 호출 가능

 - private : 오직 컨트랙트 안에 정의된 함수에서만 사용가능

 - internal : inetrnal 함수를 상속받은 컨트랙트 안에서 사용가능

 - external :오직 다른 컨트랙트나 게정에 의해서만 호출이 가능

* 상태변수는 public, private, internal 에서 선언 가능함(external에서는 안됨)

 

3.1 Private : private 속성은 해당 컨트랙트에서만 사용할 수 있음(이 컨트랙트를 상속받아서 사용하는 경우 접근 불가)

 

3.2 Internal : internal의 경우는 현재 컨트랙트 및 이 컨트랙트를 상속받은 경우에도 사용가능

 

3.3 Public : public은 현재 컨트랙트, 그리고 이 컨트랙트를 상속받은 컨트랙트, 그리고 다른 컨트랙트 및 계정에 의해서 사용가능

3.4 External : external은 다른 컨트랙트나 계정에 의해서 사용가능

3.5 상태변수 : 상태변수 역시 private, internal, public 속성부여가 가능함

     - 상태변수의 경우 external은 불가.

 

3.6 상속받아서 사용하는 예(internal 속성 상속)

 - 상속받은 경우, private함수 및 상태변수에 접근이 안됨.

 - 부모 컨트랙트에 선언된 internal 함수의 경우에는 접근 가능.

전체소스

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

contract Base {
    // Private function can only be called
    // - inside this contract
    // Contracts that inherit this contract cannot call this function.
    function privateFunc() private pure returns (string memory) {
        return "private function called";
    }

    function testPrivateFunc() public pure returns (string memory) {
        return privateFunc();
    }

    // Internal function can be called
    // - inside this contract
    // - inside contracts that inherit this contract
    function internalFunc() internal pure returns (string memory) {
        return "internal function called";
    }

    function testInternalFunc() public pure virtual returns (string memory) {
        return internalFunc();
    }

    // Public functions can be called
    // - inside this contract
    // - inside contracts that inherit this contract
    // - by other contracts and accounts
    function publicFunc() public pure returns (string memory) {
        return "public function called";
    }

    // External functions can only be called
    // - by other contracts and accounts
    function externalFunc() external pure returns (string memory) {
        return "external function called";
    }

    // This function will not compile since we're trying to call
    // an external function here.
    // function testExternalFunc() public pure returns (string memory) {
    //     return externalFunc();
    // }

    // State variables
    string private privateVar = "my private variable";
    string internal internalVar = "my internal variable";
    string public publicVar = "my public variable";
    // State variables cannot be external so this code won't compile.
    // string external externalVar = "my external variable";
}

contract Child is Base {
    // Inherited contracts do not have access to private functions
    // and state variables.
    // function testPrivateFunc() public pure returns (string memory) {
    //     return privateFunc();
    // }

    // Internal function call be called inside child contracts.
    function testInternalFunc() public pure override returns (string memory) {
        return internalFunc();
    }
}

 

소스출처 :  https://solidity-by-example.org/ 

 

블록체인 교육 문의는 아래 링크 참고 바랍니다. 

https://kimsfamily.kr/414

 

블록체인 교육 커리큘럼 및 프로필

안녕하세요 제 프로필을 간략하게 정리하였습니다. 비즈니스 문의는 dannykim@kakao.com 으로 연락주시기 바랍니다. 감사합니다. 프로필) 블록체인 강의 경력) 1. 블록체인 강의 (20년~현재) 2022년  -

kimsfamily.kr

 

반응형

댓글0