💡 오버로딩, 오버라이딩, 가상 함수
오버라이딩 : 주로 상속에서 쓰이며, 동일한 함수명에 대해 원래 기능을 무시하고 새롭게 재정의하는 것.
오버로딩 : 동일한 함수명을 가진 함수를 매개변수를 달리 해 여러개로 정의하는 것.
오버로딩과 오버라이딩은 헷갈리기 쉽다. 표로 정리해보자
오버로딩(overloading) | 오버라이딩(overriding) | |
---|---|---|
매개변수 | 변경 | 변경 X 함수 원형 유지동 |
동작 기능 | 기능 유지 | 기능 변경 또는 확장 |
오버로딩 시 함수의 기능을 변경해도 되지만, 주로 동일한 기능을 다양한 인자를 받아들여 쓰기 위해 사용하는 경우가 대부분.
상속을 통해 물려받은 멤버 함수를 오버라이딩을 통해 재정의할 것이다.
#include <iostream>
class Person {
private:
std::string name;
public:
Person(std::string n) : name(n) {};
void printInfo() {
std::cout << "name : " << name << std::endl;
}
};
class Student: public Person {
private:
int stu_num;
public:
Student(std::string n, int sn) : Person(n), stu_num(sn) {};
void printInfo() {
Person::printInfo();
std::cout << "studnet number : " << stu_num << std::endl;
}
};
int main() {
Student sujilee("sujilee", 14);
sujilee.printInfo();
std::cout << std::endl;
sujilee.Person::printInfo();
}
Person에 정의된 함수 printInfo()와 동일한 원형을 지니고, 기능부분을 학번까지 출력하도록 재정의 했음.
//OUTPUT
name : sujilee
studnet number : 14
name : sujilee
위의 코드에서 main문을 조금 바꿔보자.
int main() {
Person *pointedPerson;
Person kchoi("kchoi");
Student sujilee("sujilee", 14);
pointedPerson = &kchoi;
pointedPerson->printInfo();
std::cout << std::endl;
pointedPerson = &sujilee;
pointedPerson->printInfo();
}
클래스 포인터 변수를 생성했다. 포인터 변수에 Student 클래스의 객체를 참조하게 하면 Student 클래스의 오버라이딩 된 printInfo()가 아니라 Person 클래스의 printInfo()가 호출되는 것을 출력결과에서 확인할 수 있다.
name : kchoi
name : sujilee
클래스 포인터 변수는 해당 변수의 타입에 해당하는 클래스의 멤버만 호출할 수 있다.
위와 같은 경우를 해결하는 방법이 바로 virtual 함수 (가상 함수)를 이용한 오버라이딩이다.
#include <iostream>
class Person {
private:
std::string name;
public:
Person(std::string n) : name(n) {};
virtual void printInfo() {
std::cout << "name : " << name << std::endl;
}
};
class Student: public Person {
private:
int stu_num;
public:
Student(std::string n, int sn) : Person(n), stu_num(sn) {};
virtual void printInfo() {
Person::printInfo();
std::cout << "studnet number : " << stu_num << std::endl;
}
};
int main() {
Person *pointedPerson;
Person kchoi("kchoi");
Student sujilee("sujilee", 14);
pointedPerson = &kchoi;
pointedPerson->printInfo();
std::cout << std::endl;
pointedPerson = &sujilee;
pointedPerson->printInfo();
}
함수 타입에 virtual
키워드를 붙여주었다.
name : kchoi
name : sujilee
studnet number : 14
virtaul을 이용하여 함수를 가상 함수로 선언하면, 포인터 변수의 타입(25번째줄의 Person)이 아닌 포인터가 실제로 담고있는 객체(34번째줄의 sujilee)의 주소에 따라 호출하는 대상을 바꿀 수 있다.
가상함수에 관련해 알아야할 동적 바인딩(dynamic binding)과 가상 소멸자(virtual destrucor)에 대해서는 다음 게시물에서 다루도록 하겠다.