• 가상함수란?

    • C++ 클래스에서 virtual 키워드를 사용하는 함수

    • virtual 키워드를 이용하면!! 동적 바인딩이 됨.

    • 동적 바인딩이란 ? (출처: http://itguru.tistory.com/210)

      • 컴파일 시에 어떤 함수가 실행될 지 정해지지 않고, 런타임 시에 정해지는 일을 가리켜서 동적 바인딩(dynamic binding)이라고 부릅니다.

        
      #include <iostream>
      #include <string>
      using namespace std;

      class Parent
      {
      string s;
      public:
      Parent () : s("부모")
      {
      cout << "부모 클래스" << endl;
      }

      virtual void what() { cout << s << endl;}
      };
      class Child : public Parent
      {
      string s;

      public:
      Child () : s("자식"), Parent()
      {
      cout << "자식 클래스" << endl;
      }

      void what() { cout << s << endl;}

      };
      int main()
      {
      Parent p;
      Child c;

      Parent* p_c = &c;
      Parent* p_p = &p;

      cout << " == 실제 객체는 Parent == " << endl;
      p_p->what();

      cout << " == 실제 객체는 Child == " << endl;
      p_c->what();

      return 0;
      }

      41번째 코드 p_c->what()의 출력은 "자식"이다. 이유는 동적 바인딩이 되기 때문이다. virtual 키워드를 사용하지 않았을 때는 p_c->what()은 출력은 "부모"이다. 이유는 p_c가 부모의 포인터이기 때문에 컴파일러는 '부모의 포인터네? 부모의 함수를 실행해야지.'라고 생각을 하기 때문이다. 하지만 virtual키워드를 넣으므로써 컴파일러는 한번 더 생각하게 된다. '부모의 포인터네? 어 근데.. 이게 부모의 객체가 맞을까? 아니네 자식을 출력하자'라고 생각하게 되는 것이다.

    • 사실 클래스의 상속을 사용함으로써 중요하게 처리해야 되는 부분이 있습니다. 바로, 소멸자를 가상함수로 만들어야 된다는 점입니다.

        
      #include <iostream>
      using namespace std;

      class Parent
      {
      public :
      Parent()
      {
      cout << "Parent 생성자 호출" << endl;
      }
      ~Parent()
      {
      cout << "Parent 소멸자 호출" << endl;
      }
      };
      class Child : public Parent
      {
      public:
      Child() : Parent()
      {
      cout << "Child 생성자 호출" << endl;
      }
      ~Child()
      {
      cout << "Child 소멸자 호출" << endl;
      }
      };
      int main()
      {
      cout << "--- 평범한 Child 만들었을 때 ---" << endl;
      {
      Child c;
      }
      cout << "--- Parent 포인터로 Child 가리켰을 때 ---" << endl;
      {
      Parent *p = new Child();
      delete p;
      }
      }

      30번째 코드는 Child c;에서 부모 생성자 -> 자식 생성자 호출이 되고, }에서 지역이 끝나므로 소멸자가 호출이된다. 이때 자식 소멸자 -> 부모 소멸자 순으로 호출이된다. 근데 문제는 아래의 34번째 코드에서 발생한다. Parent *p = new Child();에서 delete p;를 호출한다면 자식의 소멸자가 아닌 부모의 소멸자가 호출(부모의 소멸자가 호출되기 때문에 자식의 메모리 누수가 발생한다)이 된다. 하지만 이 소멸자들을 virtual로 선언을 해주면 우리가 원하는 30번째 코드처럼의 호출이 가능해진다.

      이와 같은 연유로, 상속될 여지가 있는 Base 클래스들은 (위 경우 Parent), 반드시 소멸자를 virtual 로 만들어주어야 나중에 문제가 발생할 여지가 없게 됩니다.

      (출처: http://itguru.tistory.com/211 [Programming IT])

  • 순수 가상함수함수와 추상 클래스

      
    class Animal
    {
    public:
    Animal() {}
    virtual ~Animal() {}
    virtual void speak() = 0;//순수 가상함수 (자바의 추상 메소드)
    };

    추상 클래스란? 순수 가상함수를 적어도 하나 이상 포함하고 있는 함수를 추상클래스라고 함.(자바랑 같음, 여기서 순수 가상함수란? 자바의 추상 메소드와 같음, 즉 구현이 안되어있어야함. cpp에서는 virtual void 함수명 = 0;으로 순수가상함수임을 알림)


'언어, git > C++' 카테고리의 다른 글

Const(상수) 선언 위치  (0) 2019.03.26
복사 생성자  (0) 2017.11.19

+ Recent posts