[C++] 함수 Basic - 참조자, 디폴트 인수, 오버로딩

2022. 6. 24. 12:48♣ C++

이번 포스팅에선 함수 참조자, 디폴트 인수, 오버로딩에 대해 알아보도록 하겠습니다.

참조자: &를 말합니다. 대상의 원본을 직접 가져오는 역할을 합니다.

디폴트 인수: 함수의 기본으로 설정된 초기 인수를 말합니다.

오버로딩: 같은 이름의 함수를 중복하여 정의하는 것을 말합니다.

 

개발 환경 : VSCode, Windows 10

 

 

 

 

 

기본 개발 세팅은 다음과 같습니다.

#include <iostream>
#include <string.h>
#include <string>
using namespace std;

int main()
{
	return 0;
}

 

 

 

 

 

📌 참조자(&)

 

참조자는 특정 변수의 실제 이름 대신 사용할 수 있습니다.

주로 크기가 큰 구조체와 같은 데이터를 함수의 인수로 전달할 때 사용합니다.

 

 

(1) 참조자 선언

참조자는 타입을 식별하기 위해 사용하는 식별자 역할을 합니다.

int&는 int형 변수에 대한 참조를 뜻합니다. 참조자의 타입 = 변수의 타입

int a = 30;
int& a_refer = a;

string b = "C++";
string& b_refer = b;

참조자는 선언과 동시에 초기화되어야 하며, 한 번 초기화되면 참조 대상을 변경시킬 수 없습니다.

 

 

참조자를 변형시키면 어떻게 될까요?

a_refer += 100;
b_refer += " 좋아";
cout << "a_refer 변형 : " << a_refer << ", b_refer 변형 : " << b_refer << endl;
cout << "a : " << a << ", b : " << b << endl;

 

 

결과

a_refer 변형 : 130, b_refer 변형 : C++ 좋아

a : 130, b : C++ 좋아

a, b 참조자도 값이 변했지만 a,b 원본 값도 변한 것을 확인할 수 있습니다.

이로써 참조자를 이용해 값을 변화시키면 원본도 같이 변한다는 것을 알 수 있습니다.

 

 

 

 

(2) 함수의 인수로서 전달

참조자를 이용해서 함수의 인수로 전달할 수 있습니다.

앞서 확인했듯이 참조자를 변형시키면 원본도 변형되기에, 함수 안에서 원본을 변형시킬 수 있습니다.

// 함수의 원형
void Add(double&, double&);

// main() 함수 본문
int main()
{   
    double a = 30;
    double b = 20;
    Add(a, b);
    cout << "func's result : " << a << ", " << b << endl;
} 


// 함수 정의
void Add(double& a, double& b)
{
    a = a + 10;
    b = b + 5;
}

함수 원형과 정의에서 인수 타입 앞에 &를 붙여주면 끝입니다.

 

 

결과

func's result : 40, 45

참조자를 인수로 전달하고, 함수 내에서 값을 변형한 결과 실제 원본도 바뀐 것을 알 수 있습니다.

 

 

 

 

(3) 구조체의 참조

참조자는 주로 구조체같은 사용자 정의 타입을 다룰 때 유용합니다.

사용방법은 똑같으며, 함수 내부에서 구조체를 직접 변형할 필요가 없을 때는 const 키워드를 사용합니다.

 

 

책 제목과 본문을 구조체로 만들어서 예시를 만들었습니다.

struct blog
{
    string title;
    string main;
};

// 함수의 원형
void Add(const blog&);

// main() 함수 본문
int main()
{   
    blog my_blog = {"왜 C++인가?", "나는 무지렁이라서"};
    Add(my_blog);
} 


// 함수 정의
void Add(const blog& b)
{
    cout << "blog's title is " << b.title << endl;
    cout << "blog's main is " << b.main << endl;
}

쓰는 방법 자체는 앞부분과 같습니다.

함수 내부에서 변형이 필요없다면 const 키워드만 앞에 붙여주면 됩니다.

 

 

결과

blog's title is 왜 C++인가?
blog's main is 나는 무지렁이라서

 

 

 

 

 

📌 함수의 디폴트 인수

 

함수는 디폴트 인수를 지정할 수 있습니다. 디폴트 인수는 미리 내정되어 있는 함수의 초기 인수를 말합니다. 사용자가 디폴트 인수를 다른 것으로 설정하면 그대로 따라갑니다. 하지만 사용자가 별다른 설정이 없는 경우, 디폴트 값이 그대로 인수로 여겨집니다.

// 가능
int Add(int, int, int, int d = 100);

// 불가
int Add(int, int b = 200, int, int d = 100);

디폴트 인수는 함수 원형에서만 지정할 수 있습니다.

오른쪽에서 시작하여 순서대로만 지정이 가능하며, 가운데 인수들만 별도로 디폴트 인수를 지정할 순 없습니다.

 

 

다음은 디폴트 인수 사용 예시입니다.

int Add(int, int, int, int d = 100);

// main() 함수 본문
int main()
{   
    int a = 30, b = 40, c = 50;
    cout << "result : " << Add(a, b, c);
} 


// 함수 정의
int Add(int a, int b, int c, int d)
{
    int result = a + b + c + d;
    return result;
}

Add 함수에는 3개의 인수만 전달한 것을 볼 수 있습니다.

이렇게 3개만 전달해도, 4번째 인수는 디폴트 인수이기에 문제없이 돌아갑니다.

 

 

결과

result : 220

 

 

 

 

 

📌 함수 오버로딩

 

함수 오버로딩은 같은 이름의 함수를 중복하여 정의하는 것을 말합니다.

즉, 여러 함수를 하나의 이름으로 연결 짓습니다. 이는 객체 지향 프로그래밍의 특징 중 다형성을 구현한 것입니다.

 

알아야 하는 용어

함수 시그니처란? 함수의 원형에 명시되는 매개변수 리스트를 말합니다. 

* 함수 오버로딩은 서로 다른 시그니처를 갖는 여러 함수를 같은 이름으로 정의하는 것

 

 

함수 오버로딩이 어떻게 작동하는지 예시를 보며 알아보겠습니다.

int Add(int, int);
int Add(int, int, int);
void Add(string, string);
double Add(double, double);
int Add(string, int, string, int);

먼저 이름은 Add지만 시그니처가 다른 함수들의 원형을 정의합니다.

 

 

이제 모든 Add 함수를 정의해줍니다.

// 함수 정의
int Add(int a, int b){return a + b;}
int Add(int a, int b, int c){return a + b + c;}
void Add(string a, string b){printf("%d, %d\n",(a, b));}
double Add(double a, double b){return a + b;}
int Add(string a, int b, string aa, int bb)
{
    cout << a << b << "의 result : " << b + bb << endl;
    return b + bb;
}

각기 다른 인수, 다른 기능을 수행하는 함수들입니다.

 

 

이들을 본문에서 사용하면 어떻게 될까요?

// main() 함수 본문
int main()
{   
    int a = 30, b = 40, c = 50;
    string aa = "C++", bb = "과제";
    double aaa = 3.14, bbb = 3.456;
    cout << "Add(a, b) : " << Add(a, b) << endl;
    cout << "Add(a, b, c) : " << Add(a, b, c) << endl;
    Add(aa, bb);
    cout << "Add(aaa, bbb) : " << Add(aaa, bbb) << endl;
    cout << "Add(aa, a, bb, b) : " << Add(aa, a, bb, b) << endl;
}

본문에선 딱히 해줄 게 없습니다. 그저 함수의 시그니처에 맡게 인수를 전달할 뿐입니다.

 

 

결과

Add(a, b) : 70        
Add(a, b, c) : 120    
6422160, 15
Add(aaa, bbb) : 6.596 
C++30의 result : 70   
Add(aa, a, bb, b) : 70

함수 이름은 같았지만 결과는 모두 달랐습니다.

이는 C++ 자체가 함수 오버로딩 기능을 수행하기에 가능한 것입니다. 시그니처를 기준으로 Add 함수들을 분류하고 그에 맞게 과제를 수행했음을 알 수 있습니다.

함수 오버로딩은 서로 다른 타입의 인수여도 작동하지만, 인수 개수가 달라도 작동함을 확인했습니다.

 

 

 

지금까지 함수 참조자, 디폴트 인수, 오버로딩에 대해 알아봤습니다.

다음 포스팅에선 인라인 함수에 대해 알아보겠습니다.

수고하셨습니다.