가상함수

김대익·2022년 3월 6일
#include <iostream>
using namespace std;

class Animal {
public:
	Animal() {
    	cout << "animal constructor" << endl;
    }
    ~Animal() {
    	cout << "animal destructor" << endl;
    }
}

class Cat : public Animal {
public:
	Cat() {
    	cout << "cat constructor" << endl;
    }
    ~Cat() {
    	cout << "cat destructor" << endl;
    }
}

int main() {
	Animal animal;
}

animal 객체를 만들어 빌드해보면

이렇게 animal 생성자 소멸자가 실행되는 것을 알 수 있고
Cat class를 이용한 객체를 만들어보면

Animal * animalPtr = new Animal();
delete animalPtr;
을 하여 heap메모리에 Animal, Cat 객체를 만들어보면


같은 결과를 얻는다.


상속을 쓰는 이유 중 하나인 dynamic polymorphism
코드를 보면
Animal * polyCat = new Cat();
delete polyCat;

이는 base class의 형태를 갖는 포인터의 derived class를 생성했다는 뜻
heap위에 Cat 객체가 생성되었다.
이를 빌드해보면

cat 소멸자가 실행되지않는다

이는 base class의 소멸자는 virtual public, protected로 선언되어야하기 때문이다.
소멸자를 protected로 선언하면 base class를 객체로 만들지 않겠다는 뜻이므로 그런 특성이 필요할 때만 사용하고 대부분 virtual public으로 선언


virtual public의 경우

이렇게 소멸자에 virtual을 붙여주면 되고
이러고
Animal * polyCat = new Cat();
delete polyCat;
를 빌드하면

제대로 나오게 된다.


virtual이 없다면
어떠한 객체를 만들지 컴파일시간에 결정했다면
virtual이 있으면 상속과 virtual을 통해 runtime과정에 결정한다.
이를 dynamic polymorphism이다.

#include <array>
#include <iostream>

class Animal
{
public:
	virtual void speak()
	{
		std::cout << "Animal" << std::endl;
	}
	virtual ~Animal()=default;
};

class Cat : public Animal
{
public:
	void speak() override 
	{
		std::cout << "meow~" << std::endl;
	}
};

class Dog : public Animal
{
public:
	void speak() override 
	{
		std::cout << "bark!" << std::endl;
	}
};

int main()
{
	//smartPtr
	std::array<Animal*,5> animals;

	for(auto & animalPtr : animals)
	{
		int i=0;
		std::cin >> i;
		if(i==1)
		{
			animalPtr = new Cat();
		}
		else
		{
			animalPtr = new Dog();
		}
	}
	for(auto & animalPtr : animals)
	{
		animalPtr->speak();
		delete animalPtr;
	}
}

이렇듯 개수는 정해져있지만 어떤 객체를 만들지는
컴파일시간이 아니라 runtime시간에 결정된다는 것이다.

0개의 댓글