polymorphism
[C++] Virtual Table (가상 테이블)과 Dynamic Polymorphism (동적 다형성)
클래스의 크기(Memory Size)를 통해서 Virtual Table 혹은 vTable에 대해서 알아보자.
먼저 아래 코드를 보면
#include <iostream>
class Animal
{
public:
void speak()
{
std::cout << "Animal\n"
}
private:
double height;
};
int main()
{
std::cout << sizeof(Animal) << '\n';
return 0;
}
*double의 크기는 8바이트로 간주
main함수에서 sizeof() 연산자를 이용하여 Animal클래스의 크기를 출력을 해보면 8바이트가 출력이 된다. 이는 Animal클래스가 private 하게 가지고 있는 double형 멤버 변수 height에 의한 것이다.
어쩌면 의문이 드는 것이 spaek() 함수에 대한 메모리는 저장이 되지 않는 것인가?이다. 멤버 함수는 일반 함수와 동일하게 "code"영역에 저장이 되게 된다. 객체가 생성될 때마다 매번 멤버 함수가 할당이 되면 비효율적이기 때문에 "code"영역에 저장하고 공유를 한다.
저번 포스팅에서 공부한 Virtual Function을 이용하여 상속이 될 경우 클래스의 크기는 어떻게 변할까?
class Animal
{
public:
virtual void speak()
{
std::cout << "Animal" << std::endl;
}
private:
double hetght;
};
class Dog : public Animal
{
public:
virtual void speak() override
{
std::cout << "Woof" << std::endl;
}
private:
double weight;
};
int main()
{
std::cout << "Animal size : " << sizeof(Animal) << std::endl;
std::cout << "Dog size : " << sizeof(Dog) << std::endl;
return 0;
}
위 코드를 실행시켜볼 경우 Animal 클래스의 사이즈는 16바이트, Dog 클래스의 사이즈는 26바이트로 출력이 된다. 이는 Virtual Function을 사용하여 Virtual Table이 생성이 되고 이를 가리키는 pointer가 객체의 메모리 영역에 생기기 때문이다.
이해하기 쉽게 아래 그림으로 클래스에서 어떻게 Virtual Function이 호출이 되는지 그림으로 나타냈다.
Dynamic Polymorphism (동적 다형성)
프로그래밍에서 말하는 다형성은 사실 생물학에서 가져온 용어이다. 동일한 종(species) 중에서도 다양한 변이를 가지는 현상을 만한다. C++에서는 Polymorphism은 동일한 객체 혹은 함수가 특정 상황에서는 다른 게 작동하는 것을 의미한다. 우리는 이미 이런 특성을 공부하지 않았는가? 결국엔 객체들이 Polymorphism을 가지게 하기 위해서는 Virtual Function을 Override 함으로써 다형성을 얻을 수 있다.
그럼 여기서 Dynamic은 무엇을 뜻하느냐? Polymorphism을 Compile-time이 아닌 Run-time에 얻는 것을 의미한다. C++ 같은 객체지향 언어는 상속이 이루어진 클래스의 Base클래스 포인터 타입에 Derived 클래스의 주소를 가리키는 것이 가능하기 때문에 동적으로 다형성을 취득할 수 있다.
아래 코드는 Virtual Function으로 Polymorphism을 가지게 하고 Animal 포인터 타입 변수로 사용자의 입력에 따라 동적으로 객체를 생성하게 하여 Dynamic Polymorphism을 얻게 한 코드이다.
#include <iostream>
class Animal
{
public:
virtual void speak() const
{
std::cout << "Animal" << std::endl;
}
private:
double hetght;
};
class Dog : public Animal
{
public:
virtual void speak() const override
{
std::cout << "Woof" << std::endl;
}
private:
double weight;
};
int main()
{
Animal* animalPtr = nullptr; //Animal *형 변수를 만들어 null pointer로 초기화
int i;
std::cout << "which one do you want to create?\n1. Animal\n2. Dog\n";
std::cin >> i;
if (i == 1)
{
animalPtr = new Animal();
}
else if (i == 2)
{
animalPtr = new Dog();
}
//사용자가 1을 넣으면 Animal객체가 생성이 되고 2를 입력하면 Dog객체가 생성이 된다
//동적으로 만들어진 객체는 Heap영역에 생성이 되고 stack영역에 있는 animalPtr이 객체를 가리키게 된다.
animalPtr->speak();
delete animalPtr; //동적할당 메모리 해제
return 0;
}
Ref.
'Modern C++' 카테고리의 다른 글
[C++] Multiple Inheritance (다중 상속) (0) | 2021.08.21 |
---|---|
[C++] Pure Virtual Function (순수 가상 함수), Abstract Class (추상 클래스) (0) | 2021.08.20 |
[C++] Virtual Function (가상 함수) (0) | 2021.08.20 |
[C++] Class Access Specifier (클래스 접근 제한자) (0) | 2021.08.20 |
[C++] Class Keywords (클래스 키워드) : const, explicit (0) | 2021.08.19 |