Programming Tools/C++

[C++] Const 총 정리 - 2

LiDARian 2021. 6. 13. 18:10
반응형

Const와 함수

 

함수에서 Const가 사용되는 위치는 세 군데

  1. 매개변수 자료형
  2. 함수선언
  3. 리턴 자료형

 


  1. 매개변수 자료형에 사용되는 경우
PrintAddress(int &IParam)
add(const int a, const int b)

형태와 같이 매개변수의 자료형에 const가 사용된다.

함수의 파라미터를 함수 내에서 변경하면 안되므로 오류를 막기위해 사용한다.
즉, 함수내에서 파라미터를 읽기만 하고 변경을 하는일이 없다는 것이다.

 


 

함수에 전달되는 parameter를 in-parameter와 out-parameter 두가지로 구분할 수 있다.
in-parameter는 함수가 데이터를 전달받아 사용하는 것을 의미하고
out-parameter는 함수가 데이터를 변경하는 것을 의미한다.

 

예를 들면

num은 여기서 in parameter이다.

#include <iostream>
using namespace std;

void print(int num){
    cout << num << endl;
}

void main(){
    int num = 10;
    print(num);
}

num은 여기서 out parameter이다.

#include <iostream>
using namespace std;

void change(int num){
    *num = 1;
}

void main(){
    int num = 10;
    change(&num);
}

따라서 in-parameter는 값전달, 주소전달, 레퍼런스 전달
out-parameter는 주소전달, 레퍼런스 전달을 이용할 수 있겠다.

 

이 때 in parameter를 주소/레퍼런스를 통해서 전달하고자 할 때 값이 변경 될 것 같으면 const를 사용하면 된다.
이러면 print 함수 안에서는 파라미터의 값을 변경할 수 없다.

#include <iostream>
using namespace std;

void print(const int& num){
    cout << num << endl;
}

void main(){
    int num = 10;
    print(num);
}

in-parameter로 전달할때에는 const를 쓰는 것이 무조건 이득이다.

 


  1. 함수 선언에 사용하는 Const

이 경우는 클래스의 멤버함수에만 적용된다.


const 멤버 함수 내에서 멤버 변수의 값 변경을 막는다.

예를 들면,

class A{
private:
    int x, y;
public:
    void print() const {...} ; // Const 멤버함수 ! 이 함수 내에서 멤버변수 x, y의 변경이 불가하다. 
}

Const 멤버함수와 비 const멤버함수는 중복될 수 있다.

Const객체들은 const 멤버함수만 호출할 수 있다.
멤버함수는 객체 상태를 변경할 수 있는 권한을 가지고 있기 때문이다. 따라서 Const 객체는 자신의 객체 상태를 변경하면 안되기에, const 멤버 함수만 호출할 수 있다.

 

참고로 non-const 객체는 일반함수가 우선으로 호출된다. 아래 예시를 보자.

#include <iostream>

using namespace std;

class Test{
private:
    int x, y;
public:
    Test(void){}
    Test(int _x, int _y) : x(_x), y(_y){}
    void Print(void){
        x = 5;
        y = 5;
        cout << x << "," << y << endl;
    }
    void Print(void) const{
        cout << x << "," << y << endl;
    }
};

int main(void){
    const Test test1(1,2);
    Test test2(3,4);

    test1.Print();
    test2.Print();
}

출력 :
1,2
5,5

 


  1. 리턴 자료형에서 사용하는 const
const int& GetX() { return x; }

와 같은 형식으로 작성한다. 아래와 같이 const한 변수를 반환하므로, 반환된 값을 변경할 수는 없다.

#include <iostream>
using namespace std;

class Test
{
private:
    int x,y;
public:
    Test(void) {}
    Test(int _x,int _y)
        :x(_x),y(_y)
    {}
    const int& GetX(void) // 반환형에 const
    {
        return x;
    }
};

int main(void)
{
    Test test1(1,2);
	cout << test1.GetX() << endl;
    // test1.GetX() = 10; // 반환받은 x에 10을 대입하는 명령. 하지만 const한 x를 돌려받으므로 바로 에러가 난다.
    cout << test1.GetX() << endl;
    return 0;
}

 

만약 const 지시어를 없앴다면 이렇게 반환된 값에 대해 변경이 가능할 것이다.

 

#include <iostream>
using namespace std;

class Test
{
private:
    int x,y;
public:
    Test(void) {}
    Test(int _x,int _y)
        :x(_x),y(_y)
    {}
    // const int& GetX(void) // 반환형에 const
    // {
    //     return x;
    // }
	int& GetX(void) // 반환형에 const
    {
        return x;
    }
};

int main(void)
{
    Test test1(1,2);
	cout << test1.GetX() << endl;
	test1.GetX() = 10; // 반환받은 x에 10을 대입하는 명령. 하지만 const한 x를 돌려받으므로 바로 에러가 난다.
	cout << test1.GetX() << endl;
    return 0;
}

출력 :

1
10


함수 argument 전달시에 const& 로 전달하는 경우에 대해서 알아보자.

객체를 파라미터로 사용하는 경우 ( call by-value )

값을 복사하여 전달하므로 임시 복사본이 생성되며 함수 소멸시 사라진다.
C++의 경우, 복사생성자가 호출된다. 복사본이 생기므로 2개의 변수가 존재하는 상황이 발생한다.

참조(&)를 파라미터로 사용하는 경우 ( call by reference )

실제 data 원본을가지고 사용하므로 복사 생성자가 호출되지 않는다.
하지만 data 원본이므로 함수 내에서 값이 변경될 수 있다.
이 경우 한 개의 변수가 존재하며 2개의 이름을 가지게 된다. (함수인자명, 원본명)

Const 참조(&)를 파라미터로 사용하는 경우 ( call by reference to const )

const 사용으로 실수로 함수 안에서 값이 변경되는것을 막을 수 있다.
실제 data원본이므로 복사 생성자가 호출되지도 않는다.

 

 

 

 

반응형