# 상속 (Inheritance)
# 오버로딩(Overloading)과 오버라이딩(Overriding)
# 가상함수, 순수가상함수 (Virtual Function, Pure Virtual Function)
# 멤버이니셜라이저 (Memeber Initializer)
# 가상함수(Virtual Function)
class A { public: void Message() { std::cout << "class A" << std::endl; } }; class B : public A { public: void Message() { std::cout << "class B" << std::endl; } }; int main() { A a; B b; A *aa = &a; A *bb = &b; aa->Message(); bb->Message(); return 0; }
class A { public: virtual void Message() { std::cout << "class A" << std::endl; } }; class B : public A { public: void Message() { std::cout << "class B" << std::endl; } }; int main() { A a; B b; A *aa = &a; A *bb = &b; aa->Message(); bb->Message(); return 0; }
int main() { int num; Monster *monster = nullptr; std::cin >> num; switch(num) { case 1: monster = new Pig(); break; case 2: monster = new Slime(); break; } return 0; }
int main() { int num; std::cin >> num; switch(num) { case 1: { Pig *p = new Pig(); break; } case 2: { Slime *s = new Slime(); break; } } return 0; }
#include <iostream> using namespace std; class A { public: virtual void function1() { std::cout << "A의 function1" << std::endl; } virtual void function2() { std::cout << "A의 function2" << std::endl; } virtual void function3() { std::cout << "A의 function3" << std::endl; } }; class B : public A { virtual void function2() { std::cout << "B의 function2" << std::endl; } virtual void function3() { std::cout << "B의 function3" << std::endl; } virtual void function4() { std::cout << "B의 function4" << std::endl; } }; int main() { A *b = new B(); b->function1(); b->function2(); b->function3(); // b->function4(); return 0; }
여기서 자세한 설명을 하겠습니다.
A클래스에 virtual이 있다.
A클래스의vtable 생성
vtable을 가리키는 vptr생성
vtable에는
function1()
function2()
function3()
저장
B클래스에 virtual이 있다.
B클래스의 vtable을 생성
A클래스를 상속받으므로 A클래스의 vtable도 상속
A클래스의 vtable에
function1()
function2()
function3() 가 있는데
B클래스에는
function2()
function3() 이 재정의됨
function4() 추가
B클래스의 vtable에
function1() B클래스에없으므로 A를 가리키고잇음
function2() B를 가리킴
function3() B를 가리킴
function4() B를 가리킴
이렇게 진행이된다.
그렇지만 코드에서
A *b = new B();
a는 A포인터이다.
마지막행에서
b->function4()는 할수 없다. 컴파일에러이다
왜냐하면
A에는 function4()함수가 없기 때문이다.
그림을 참고하면 이해가 쉬울것이다.
[출처] http://www.learncpp.com/cpp-tutorial/125-the-virtual-table/
여기서 또 하나 알아야 할 점이 있습니다.
생성자, 소멸자에 관련된건데요
생성자 : 기본클래스 -> 파생클래스
소멸자 : 파생클래스 -> 기본클래스
가 된다는걸 공부했는데요
#include <iostream> using namespace std; class Animal { public: Animal() { std::cout << "Animal() 생성자" << std::endl; } virtual ~Animal() { std::cout << "~Animal() 소멸자" << std::endl; } }; class Dog : public Animal { public: Dog() { std::cout << "Dog() 생성자" << std::endl; } ~Dog() { std::cout << "~Dog() 소멸자" << std::endl; } }; int main() { Animal *a = new Dog(); delete a; }
생성자의 개수만큼 소멸자가 호출된 것을 볼 수 있는데요
virtual을 뺀다면 어떻게 바뀔까요?
~Dog() 소멸자가 보이지않습니다.
[Animal클래스의 소멸자에 virtual이 없다]
-> Dog클래스의 생성자호출을위해 Animal클래스의 생성자호출
-> Dog클래스의 생성자 호출
-> delete a;
-> a는 Animal의 포인터이기때문에 a의 소멸자가 호출
* 그렇다면 Dog()는 생성되고 제거가 되지않아서 heap메모리에 남아있게 됩니다. 뭔가 찝찝하고 상식적으로 이렇게 되면 안됩니다.
그래서 기본클래스인 Animal의 소멸자에 virtual을 붙입니다.
[Animal클래스의 소멸자에 virtual이 있다]
-> Dog클래스의 생성자호출을위해 Animal클래스의 생성자호출
-> Dog클래스의 생성자 호출
-> delete a;
-> a는 Animal의 포인터이기때문에 a의 소멸자가 호출
-> Animal의 소멸자가 virtual이기때문에 상속받는 파생클래스인 Dog의 소멸자를 호출
virtual을 쓰면 파생클래스에서 재정의될수 있으므로 탐색을 함.
그런데 파생클래스에 재정의한 소멸자가 있다면,
-> Dog클래스의 소멸자호출
-> Animal클래스의 소멸자호출
# 순수가상함수 (Pure Virtual Function)
순수가상함수란 : 구현이없는 가상함수.
그렇다면 어떻게 쓰는것일까요?
virtual void 메서드이름() = 0;
함수인데 구현이 없습니다.
이렇다는것은 실제구현은 파생클래스에서 한다는 것입니다.
주의할점은 반드시 파생클래스에서 '재정의' (= Overriding) 해야 한다는 것입니다.
또한 순수가상함수(Pure Virtual Function) 을 가지고 있는 클래스를
추상 클래스(Abstract Class) 라고 부릅니다.
여기서 추상 클래스가 되면 객체를 생성할 수 없게 됩니다.
#include <iostream> using namespace std; class Animal { public: virtual void sound() = 0; }; class Dog : public Animal { public: void sound() { std::cout << "멍멍" << std::endl; } }; int main() { Animal *a = new Dog(); }
- vTable과 vPtr의 심화
지적사항이나 부족한점 댓글로 달아주시면 고치겠습니다!
감사합니다
'복습 > C++' 카테고리의 다른 글
[C++] 복습일지 inline함수 그리고 virtual (0) | 2018.01.24 |
---|---|
[C++] 복습일지 part 2 - 4 #멤버 이니셜라이저 (0) | 2018.01.21 |
[C++] 복습일지 part 2 - 2 #오버로딩(Overloading)과 오버라이딩(Overriding) (0) | 2018.01.14 |
[C++] 복습일지 part 2 - 1 #상속(Inheritance) (0) | 2018.01.14 |
[C++] 복습일지 part 1 (0) | 2018.01.07 |