본문 바로가기
C++

[C++] 함수재정의 오버로딩(overloading)

by rehtorb_s 2020. 10. 9.

오버로딩이란 함수를 중복으로 정의한다는 뜻입니다.

오버로딩된 함수의 구분은 매개변수를 기준으로 합니다. 함수의 이름이 같지만 매개변수가 고유하다면 컴파일러가 중복된 함수를 구별할 수 있다는 뜻입니다. 이렇게 이름은 같지만 다른 기능을 하는 오버로딩은 오버라이딩 처럼 C++ 객체지향 특징중 하나인 다형성의 토대가 되는 기술인것 같습니다.

오버로딩은 크게
1. 함수 오버로딩
2. 생성자 오버로딩
3. 연산자 오버로딩
로 나뉠 수 있습니다.

사실 생성자나 연산자나 모두 함수의 범위안에 들긴하지만 엄연히 용어를 구분해서 쓰기 때문에 나눠보았습니다.

1. 함수 오버로딩(Function Overloading)

더보기
#include <iostream>
using namespace std;

int Sum(int a, int b);
double Sum(double a, double b);

int main(void)
{
	int iResult = Sum(10, 20);
	double dResult = Sum(30.1f, 20.2f);

	std::cout << "iResult : " << iResult << std::endl;
	std::cout << "dResult : " << dResult << std::endl;
	return 0;
}

int Sum(int a, int b)
{
	return a+b;
}

double Sum(double a, double b)
{
	return a+b;
}

두개의 매개변수를 인자로 받아 합을 반환하는 Sum() 함수를 오버로딩 했고, iResult(Integer)와 dResult(Double)에는 각각의 다른 Sum()함수가 호출되었습니다.

만약 함수호출시 다른 형태의 자료형이 인자로 전달된다면 어떻게 될까요? 작은 자료형은 큰 자료형으로 큰 자료형은 작은 자료형으로 암묵적인 형변환이 이뤄집니다.



2. 생성자 오버로딩(Constructor Overloading)
객체를 선언할 때 호출되는 생성자를 중복선언합니다.

더보기
#include <iostream>
using namespace std;

class CCalculator
{
public:
	CCalculator();
	CCalculator(int value1, int value2);
private:
	int a;
	int b;
};

CCalculator::CCalculator()
	:
	a(10),
	b(20)
{
}

CCalculator::CCalculator(int value1, int value2)
	:
	a(value1),
	b(value2)
{
}

int main(void)
{
	CCalculator cal1;
	CCalculator cal2(40, 50);
	
	return 0;
}



기본 생성자와 오버로딩된 생산자를 구현한 모습입니다. 어떤 객체를 어떤 방식으로 초기화를 시킬지는 여러분 마음이기 때문에 생성자를 몇개를 어떻게 중복선언하시든 상관이 없습니다. 생성자 오버로딩 역시 매개변수로 구분을 합니다.

3. 연산자 오버로딩(Operator Overloading)
연산자하면 뭐가 떠오르시나요? 사칙연산, 비트연산, 논리연산 등등 많이들 떠오르실겁니다. 연산자 오버로딩이란 이 연산들을 클래스내에서 재구성해서 내 입맛대로 사용하는 방식입니다. 단 주의해야할 특징들이 있는데

- 연산자 오버로딩 특징
a) C++ 언어 연산자만 중복 가능(+ - * / % == != 등등
Ex) (. 참조연산) ( :: 네임스페이스) 적용 안됨
b) 연산자 오버로딩으로 피연산자의 개수를 바꿀 수 없음
c) 연산자 오버로딩으로 연산의 우선순위를 바꿀 수 없음

더보기
#include <iostream>
using namespace std;

class CCalculator
{
public:
	CCalculator();
	CCalculator(int value1, int value2);
	CCalculator operator+(CCalculator op2)
	{
		CCalculator temp;
		temp.a = this->a + op2.a;
		temp.b = this->b + op2.b;

		return temp;
	}
	void Show()
	{
		std::cout << "a : " << a << std::endl;
		std::cout << "b : " << b << std::endl;
	}
private:
	int a;
	int b;
};

CCalculator::CCalculator()
	:
	a(10),
	b(20)
{
}

CCalculator::CCalculator(int value1, int value2)
	:
	a(value1),
	b(value2)
{
}

int main(void)
{
	CCalculator cal1;
	CCalculator cal2(40, 50);
	
	CCalculator result = cal1 + cal2;
	result.Show();
	return 0;
}



일반적으로 클래스 객체끼리 +연산을 한다는 것이 상상이 되시나요? 위의 연산자 오버로딩을 주석처리 하게 된다면 main문에서의 cal1 + cal2는 에러를 일으키게 되는데, 연산자 오버로딩을 구현함으로써 새로운 자료형간의 연산까지 확장할 수 있게 되었습니다.

+연산은 C = A + B의 형태를 띄는데, 해당 오버로딩의 선언을 보았을 때
CCalculator operator+(CCalculator op2); 는 컴파일러에 의해

C -> CCalculator
=
A -> 왼쪽 피연산자(this)
+ -> operator+
B -> 오른쪽 피연산자(op2)

형태로 변환이 됩니다. 함수의 구현부를 보면 this 포인터를 확인함으로써 왼쪽 피연산자가 cal1에 해당되는 것을 알 수 있습니다. 이해에 도움이 되시길 바랍니다.

위 예시 이외에도 위 특징에 위배되지 않는 한 여러분들은 여러 연산을 재정의 할 수 있습니다.

다음 포스팅은 템플릿에 대해 알아보겠습니다.



포스팅 내용에 오류가 있거나 지적사항이 있다면 댓글로 달아주세요. 배움을 멈추지 않는 Good Programmer가 되겠습니다. 감사합니다.

댓글