C++ Language [핵심정리] - 2
1. C++ 의 기본문법 - 2
오버 로드(Over load) 그러니까 다중 정의에 대해서 알아보겠습니다.
일단 우리가 항상 흔히 볼수 있는 그리고 접하는 swap 함수를 정의한 후 사용하겠습니다. 이 때 swap 함수는 std 라는 namespace에 정의되어 있기 때문에 해당 부분을 주석 처리 및 삭제하고 정의해야 합니다.
근데 여기서 swap 함수로 int 형이 아닌 자료형을 매개변수로 주고 싶다면 swap 함수(매개변수의 자료형이 다른)를 자료형에 따라 각각 정의합니다. (이 때 함수를 구분하기 위해 명칭의 수정이 필요합니다.)
#include <iostream>
// using namespace std;
void swap(int& First, int& Second) // int 형
{
int temp = First;
First = Second;
Second = temp;
}
void swap_double(double& First, double& Second) // double 형
{
double temp = First;
First = Second;
Second = temp;
}
void swap_pointer(int* (&First), int* (&Second)) // 포인터
{
int* temp = First;
First = Second;
Second = temp;
}
int main()
{
int one(10), two(20);
std::cout << " (swap 전) one -> " << one << ", two -> " << two << std::endl;
swap(one, two);
std::cout << " (swap 후) one -> " << one << ", two -> " << two << std::endl << std::endl;
double one_d(18.8), two_d(28.8);
std::cout << " (swap 전) one_d -> " << one_d << ", two_d -> " << two_d << std::endl;
swap_double(one_d, two_d);
std::cout << " (swap 후) one_d -> " << one_d << ", two_d -> " << two_d << std::endl << std::endl;
int* Ptr_First(&one), *Ptr_Second(&two); // 이 때 가리키는 주소는 포인터 자료형의 기본형과 동일해야한다.
std::cout << " (swap 전) *Ptr_First(&one) -> " << *Ptr_First << ", *Ptr_Second(&two) -> " << *Ptr_Second << std::endl;
swap_pointer(Ptr_First, Ptr_Second);
std::cout << " (swap 후) *Ptr_First(&one) -> " << *Ptr_First << ", *Ptr_Second(&two) -> " << *Ptr_Second << std::endl;
return 0;
}
- 함수 여러 개 정의
이렇게 자료형에 따라 함수가 나누어진다면 사용자 입장에서 불편할 뿐더러 실수할 가능성이 높아집니다. 때문에 C++ 에서는 over load 라는 기능을 제공하고 해당 기능을 사용하려면 동일 기능을 수행하는 함수의 명칭들을 모두 동일하게 작성해줘야 합니다.
그래도 동일한 결과가 나타는데 왜냐하면 cin 함수처럼 매개변수의 자료형을 자동으로 인식하고 해당 매개변수의 자료형에 해당하는 함수를 불러옵니다. 커서로 확인해보면
2개의 오버로드(즉, 2개의 다중정의)가 있다고 나오네요.
일단, 해당 부분의 다중 정의된 swap 함수는 서로 다른 자료형의 매개변수를 가지고 있습니다. 그래서 실제로 구분할 수 있는것이죠. 그런데 만약 오버로드 된 함수들 중 일부에서 매개변수가 중복된다면 어떻게 될까요?
에러가 발생합니다. 사실 매개변수도 동일하고, 함수명도 동일한 경우에는 두 함수를 구별한 수단이 없기 때문에 발생하는 오류라고 추측됩니다. 이 경우에는 사실 매개변수를 하나 더 추가해서 구별할 수단을 마련해주면 됩니다.
함수 매개변수로 add 를 추가하고, swap 함수를 호출했을 때 어떤 함수가 호출되는지 알아보기 위해 각 함수에 출력문을 추가했습니다. 그 결과
첫번 째의 swap 함수가 호출됨을 알 수 있습니다. 이제 매개변수로 cnt 즉, 3개의 매개변수를 준다면?
두번째 함수가 호출되었고, 이를 통해 저희는 매개변수의 개수에 따라서 호출되는 함수가 달라진다는 것 또한 알 수 있습니다. 그리고 = (할당 연산자)를 이용해 매개변수의 default 값 (기본 값)을 설정할 수 있습니다.
이처럼 할당 연산자를 이용해 디폴트 값을 설정해주면 보시는 것처럼 해당 매개변수를 따로 전달하지 않아도, 디폴트 값을 기준으로 연산한 뒤 반환합니다.
매개변수의 순서가 좌측에서 우측인것과는 반대로 디폴트 값을 할당할 때의 방향은 우측에서 좌측입니다. 따라서 다음과 같이 좌측부분의 매개변수에는 디폴트값이 설정되어있지만, 우측 부분에 디폴트값이 없다면, 에러가 발생합니다. (이 는 매개변수를 이용할 때 모호한 부분이 없게 하기 위해서입니다.)
따라서 에러 없이 사용하려면
매개변수를 읽을 때는 좌측에서 우측(→)으로 디폴트 값을 설정할 때는 우측에서 좌측(←)으로만 기억하시면 됩니다.
:: 는 속해있는 네임스페이스를 표시할 때 사용합니다.
변수 num은 전역변수이지만, 속해있는 네임 스페이스가 없기에 :: 앞을 공백으로 둡니다.
만약 이렇게 변수나 함수의 소속을 밝히지 않는다면 자신이 속한 네임 스페이스의 변수나 함수를 의미합니다. 다만 여기선 네임스페이스에 포함된 변수나 함수가 없기 때문에 가장 외부에 있는 num의 값을 수정했습니다. 당연히 네임스페이스 안에 동일한 명의 변수를 선언한다면 그 변수의 값을 수정하게 되겠죠.
여기서 중요한 점 :: 하고 앞에 공백으로 둔것(포함된 네임스페이스가 없다는 걸 의미)과 :: 을 아예 사용하지 않는 것은 완전히 다른 의미입니다.
이 코드를 예시로 들어볼게요. 변수를 클릭할 경우 동일한 변수끼리 파란 드래그 표시로 나타나는 데 확인해보면
분명히 동일한 네임스페이스에 위치해 있음에도 다른 변수들을 가리키고 있다는 걸 알 수 있습니다. 그래서 자신이 포함된 네임스페이스의 변수를 사용하고 싶다면 애초에 :: 사용하지 않던가, 아니면 자신의 네임스페이스를 :: 앞에 적어주면 됩니다.
1)
2)
그리고 네임 스페이스들은 중첩 가능합니다.
중첩 된 네임스페이스를 이용하려면 두번의 :: 접근이 필요합니다. 저희가 :: 을 생략하기 위해 using namespace 라는 걸 사용했잖아요. 이 때도 using namespace 를 사용해 :: 접근을 한 번 줄일 수 있습니다. 다만, 중첩된 네임스페이스에서 전역 변수나 함수의 명칭이 동일한 부분이 존재할 경우에는 using namespace로 :: 접근을 생략할 수 없습니다.
그러니까 공통된 명칭의 무언가를 사용할 때는 using namespace 를 사용하더라도 :: 로 접근해줘야 합니다.
그러니까 명칭이 겹치지 않는다면 다음과 같이 생략 가능합니다.
그리고 네임스페이스 안에 있는 함수의 선언과 정의부분을 분리시킬 수 있습니다.
마지막 함수의 선언부분은 다음과 같이 대체할 수 있습니다.