함수 오버로딩과 오버라이딩
함수 오버로딩
개념은 다르지만 얼핏 보기에 이름이 비슷해 가끔 헷갈리는 부분이 생기는 경우가 있음.
함수 오버로딩이란 함수의 이름은 동일하게 사용하면서 매개변수의 개수나 타입, 순서가 다를경우 발생함.
예를 들어
정수형 매개변수를 받는 함수
void printNumber(int x)
{
std::cout << "Integer: " << x << std::endl;
}
실수형 매개변수를 받는 같은 이름의 함수
void printNumber(double x)
{
std::cout << "Double: " << x << std::endl;
}
과 같이 함수의 이름은 동일하지만 매개변수의 타입이 int와 double로 다른 경우 함수 오버로딩이 구현됨
매개변수 타입이 다르다고 매번 다른 함수를 만들어 내는것보다 함수의 재 사용성을 올려주는 장점이 있음.
따라서 C++ 객체 지향 프로그래밍의 핵심인 다형성의 중요한 개념중 하나임
**
메모리적인 측면에서 보면 A 함수와 B 함수가 오버로딩을 통하여 생성되었다고 하여도
각각의 함수에 다른 메모리 주소가 할당됨.
컴파일러가 호출된 함수를 보고 어떤 함수인지를 '매개변수' 목록을 기반으로 구별함.
즉 오버로딩된 함수는 논리적인 측면에서는 하나의 함수라고 볼 수 있지만
메모리 관리적인 측면에서는 결국 다른 함수라고도 볼 수 있음.
오버라이딩
오버라이딩에서 중요한 핵심은 클래스* 와 상속* 임.
함수 오버라이딩이라는것은
기존에 정의된 부모 클래스(상위 클래스)의 *메서드를 하위 클래스에서 재정의하는 것을 의미함.
(클래스 내부의 함수는 메서드라고 부름)
메서드의 이름과 매개변수 목록, 반환값의 타입은 부모 클래스의 메서드와 일치시켜 주어야 함.
class Animal
{
public:
void bark()
{
std::cout << "동물이 소리를 냅니다." << std::endl;
}
};
class Dog : public Animal
{
public:
void bark()
{
std::cout << "강아지가 짖습니다." << std::endl;
}
};
이런 구조를 가진 부모와 자식 클래스를 만들어 두고
speak이라는 메서드를 Animal에서 정의하고
Dog에서 오버라이딩함.
int main()
{
Animal zoo;
Dog woo;
zoo.bark(); // "동물이 소리를 냅니다."
woo.bark(); // "강아지가 짖습니다."
return 0;
}
speak이라는 메서드는 dog 클래스에서 호출할 경우 오버라이딩 된 메서드가 호출됨.
오버라이딩의 핵심은 상속받을 메서드의 일부 내용을 상황에 맞게 변경하고자 할때 사용함
여기서 포인터를 사용해서 메서드를 호출할때 문제가 발생하는데
int main()
{
Animal* ptr_Z = &zoo;
Dog* ptr_D = &woo;
ptr_Z->bark();
를 실행하면 "동물이 소리를 냅니다." 가 잘 동작하지만
여기에 포인터 변수에 woo 객체의 주소값을 대입한 뒤 bark를 동작시켜도
강아지가 짖는게 아닌
ptr_Z = &woo;
ptr_Z->bark();
}
"동물이 소리를 냅니다." 가 동작함.
포인터 변수가 실제로 가리키는 객체의 타입을 기준으로 함수를 호출하는 것이 아니라,
해당 포인터의 타입을 기준으로 함수를 호출하기 때문
이럴때 가상함수인 virtual 키워드를 오버라이딩할 함수에 달아주면 의도대로 올바르게 동작함.
virtual은 사전적으로는 '가상의, 실재하지 않는' 이라는 의미임.
class Animal
{
public:
virtual void bark()
{
std::cout << "동물이 소리를 냅니다." << std::endl;
}
};
class Dog : public Animal
{
public:
void bark() override
{
std::cout << "강아지가 짖습니다." << std::endl;
}
};
로 클래스를 바꿔준 후
int main()
{
Animal zoo;
Dog woo;
Animal* ptr_Z = &zoo;
Dog* ptr_D = &woo;
ptr_Z->bark();
ptr_Z = &woo;
ptr_Z->bark();
return 0;
}
의도대로 동작하는걸 확인할 수 있음
클래스 내의 메서드를 보다가 virtual 키워드를 사용하거나 발견할 경우
항상 오버라이딩과 상속 구조의 확장에 염두에 두고 두어야 함 !