본문 바로가기
개발/C, C++

C++ - 상수형 메서드와 mutable, const_cast<>

by 피로물든딸기 2021. 7. 28.
반응형

C, C++ 전체 링크

 

링크를 참고하여 다시 아래의 코드를 보자.

여기서 printValue는 value1, value2를 출력만 할 뿐, 수정은 하지 않는다.

#include <stdio.h>
#include <iostream>

using namespace std;

class TEST
{
public:
	int value1;
	int value2;

	TEST()
	{
		cout << "생성자 호출" << endl;
		value1 = 1;
		value2 = 2;
	}

	void printValue()
	{
		cout << value1 << ", " << value2 << endl;
	}
};


int main(void)
{
	TEST test;

	test.printValue();

	return 0;
}

 

이런 경우, const 키워드를 이용하여 상수형 메서드로 만들 수 있다.

상수형 메서드는 멤버 변수를 수정할 수 없고, 상수형 메서드에서 다른 메서드가 변수를 바꾸지도 못하게 한다.

class TEST
{
public:

	...
    
	void printValue() const
	{
		value1 = 10; //compile error
		cout << value1 << ", " << value2 << endl;
	}
};

 

따라서 아래의 코드도 compile error가 발생한다.

	void setValue1(int val)
	{
		value1 = val;
	}

	void printValue() const
	{
		setValue1(5); //complie error
		cout << value1 << ", " << value2 << endl;
	}

mutable을 이용하면 상수형 메서드에서 예외로 값을 수정할 수 있다.

class TEST
{
public:
	mutable int value1;

	...
    
	void setValue1(int val) 
	{
		value1 = val;
	}

	void printValue() const
	{
		//setValue1(5); //compile error
		value1 = 5;
		cout << value1 << ", " << value2 << endl;
	}	
};

 

그러나 여전히 setValue1은 사용하지 못하는데, mutable은 상수형 메서드에서 예외를 허용하기 때문이다.

따라서 setValue1에 const 키워드를 추가하면 된다.

#include <stdio.h>
#include <iostream>

using namespace std;

class TEST
{
public:
	mutable int value1;
	int value2;
	TEST()
		: value1(1), value2(2)
	{
		cout << "생성자 호출" << endl;
	}

	TEST(int val1, int val2)
	{
		value1 = val1;
		value2 = val2;
		cout << "생성자 호출 2" << endl;
	}

	void setValue1(int val) const
	{
		value1 = val;
	}

	void printValue() const
	{
		setValue1(5); 
		//value1 = 5;
		cout << value1 << ", " << value2 << endl;
	}	
};

int main(void)
{
	TEST test = TEST(3, 4);

	test.printValue();

	return 0;
}

 

하지만 당연히 멤버 변수 수정을 하지 않기 위해 const를 사용하였으므로 mutable 사용은 자제하는 것이 좋다.


const_cast<>

 

const_cast는 상수형 포인터에서 const를 일시적으로 제거할 수 있다. 

이것은 mutable이 아닌 변수에 대해서도 가능하다.

 

위의 코드에서 setValue1을 아래와 같이 고쳐보자.

class TEST
{
public:
	mutable int value1;
	int value2;
	
    ...
    
	void setValue1(int val) const
	{
		value1 = val;
		value2 = val; //compile error
	}
};

 

setValue1 메서드가 const로 선언되었으나, value1은 mutable이므로 변환가능하다.

하지만 value2를 변형하려고 하니 compile error가 발생하게 된다.

 

아래와 같이 임시로 newValue2를 선언한 후, value2를 const_cast로 type 캐스팅하면 

const의 제한을 임시로 해제할 수 있다.

void setValue1(int val) const
{
	value1 = val;
	//value2 = val; //compile error

	int& newValue2 = const_cast<int&>(value2);
	newValue2 = val;
}

main에서 printValue를 호출하여 setValue1이 호출되었고, value2도 변경된 것을 알 수 있다.

 

최종 코드는 아래와 같다.

#include <stdio.h>
#include <iostream>

using namespace std;

class TEST
{
public:
	mutable int value1;
	int value2;
	TEST()
		: value1(1), value2(2)
	{
		cout << "생성자 호출" << endl;
	}

	TEST(int val1, int val2)
	{
		value1 = val1;
		value2 = val2;
		cout << "생성자 호출 2" << endl;
	}

	void setValue1(int val) const
	{
		value1 = val;
		//value2 = val; //compile error

		int& newValue2 = const_cast<int&>(value2);
		newValue2 = val;
	}

	void printValue() const
	{
		setValue1(5);
		//value1 = 5;
		cout << value1 << ", " << value2 << endl;
	}
};

int main(void)
{
	TEST test = TEST(3, 4);

	test.printValue();

	return 0;
}

const_cast는 const로 선언된 포인터만 해제할 수 있다.

일반 변수의 const와 함수 포인터, 멤버 함수에 대한 const는 해제할 수 없다.

아래의 value는 여전히 100임을 알 수 있다.

#include <stdio.h>
#include <iostream>

using namespace std;

int main(void)
{
	const int value = 100;
	// value = 101; compile error

	int& newValue = const_cast<int&>(value);
	newValue = 500;

	printf("%d\n", value); // 100; 해제 불가능

	return 0;
}

반응형

댓글