Hoon222y

[1219-5] 상수 멤버 함수 / mutable 본문

코딩/교육

[1219-5] 상수 멤버 함수 / mutable

hoon222y 2018. 12. 20. 00:06

상수 멤버 함수 : 함수 내부에서 멤버 변수의 값을 수정할 수 없는 함수를 말한다. 멤버 변수를 읽기만 하고 변경하지 않는다면 const 지정자를 붙여 상수 함수로 선언하면 된다. const 지정자를 함수명 뒤에 붙인다

 사용방법 : 리턴타입 함수명 ([매개변수, ...]) const 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
using namespace std;
class Point{
public:
    int _x, _y;
    Point(int x, int y) : _x(x), _y(y){};
    
    void set_x(int x){ _x = x; }
    void print() const {        //이 안에서 상태값이 변경되지 않는다는 보장을 해주기 위해서 함수 뒤에 const를 붙인다.
        cout << _x << " " << _y << endl;
        //_x = 0;               //const 를 사용했기 때문에 에러이다. 
    }
};
int main(){
    const Point p(11);
    //상수 객체의 경우, 상수 멤버 함수만 호출 가능한다.
    //이는 멤버 함수가 객체의 값을 변경하면 객체의 논리적 상수성이 무너지기 떄문인다.
    //따라서 멤버 함수중 멤버 변수의 값을 변경하지 않는 함수가 존재할 경우,
    //그 함수는 반드시 상수 멤버 함수로 선언해야 한다.
    //결론! 상수 멤버 함수는 선택이 아니라 필수이다.
    p.print();              //프린트라는 함수가 안에 있는 변수가 변하는지 안변하는지 보장이안됨.
                            //따라서 사용하고 싶다면 class안의 print 함수뒤에 const를 붙여야 한다.
}
cs


 해당 코드를 보자. class내의 print함수는 단지 출력만 할 뿐 멤버 변수를 변경하지 않는다. 따라서 const를 붙여서 그 안에서 상태값이 변경되지 않음을 보장한다. 

이 때 주의할 점이 하나있다. 상수 객체는 상수 함수만 호출할 수 있으며, 상태를 변경하는 비 상수 함수는 호출할 수 없다는 것이다.  따라서 const Point로 선언된 p 객체의 경우 set_x(int x) 함수는 사용할 수 없고, const가 붙은 print 함수만 사용이 가능한 것이다. 


 또한 알아둘 점은 상수 멤버 함수와 비상수 멤버 함수는 오버로딩이 가능하다는 사실이다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Point{
public:
    int _x, _y;
    Point(int x, int y) : _x(x), _y(y){};
    //상수 멤버 함수와 비상수 멤버 함수는 함수의 시그니처가 달라서 오버로딩이 가능하다.
    void print() {                          //void print(Point* const this)
        cout << _x << " " << _y << endl;
    }
    void print() const {                    //void print(const Point* const this)
        cout << _x << " " << _y << endl;
        //this->_x = 0; 이 안된다.
    }
};
int main(){
    const Point p(11);
    p.print();
}
cs


 하지만 객체의 상수얼과 상관없이 언제나 수정이 가능하게 할 수 있다. 

mutable : 상수 멤버 함수 안에서 값의 수정을 가능하게 하는 키워드이다. 이 속성을 가지는 멤버는 객체의 상수성과 상관없이 언제나 수정이 가능하다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
using namespace std;
 
class Point{
public:
    int _x, _y;
    mutable char str[32];
    mutable bool is_cached;
    
    Point(int x, int y) : _x(x), _y(y), is_cached(false){};
    
    //현재 객체를 문자열화 하는 함수를 구현하자. 이는 자바의 tostring과 같은 함수이다.
    //아래의 함수가 성능상의 오버헤드가 있다고 가정하면 이를 해결하기 위해 캐쉬를 도입힌다.
    const char* to_str() const{
        if (!is_cached){
            //char str[32];             // 이렇게 하면 함수가 끝나면 이게 사라지니까 위에다가 적음.
            sprintf(str, "(%d, %d)", _x, _y);
            is_cached = true;
        }
        return str;
    }
};
 
int main(){
    Point p(11);
    cout << p.to_str() << endl;
}
cs


 원래의 경우에는 st_str() const 이기 때문에 is_cashed 라는 멤버 변수를 수정할 수 없어야 하지만 mutable 을 통하여 이러한 경우에도 멤버 변수 값을 변경할 수 있다. 

Comments