const 키워드를 사용해서 변수를 심볼릭 상수(symbolic constant)로 변형할 수 있다는 것은 이미 배운바 있습니다.
또한 const를 포인터에 사용하는 방법이 두가지 있었습니다.
▶ 포인터 변수에 const 를 사용하면 포인터 변수를 변경할 수 없습니다. (포인터의 상수화)
▶ 포인터의 간접 참조연산자(indirection operator)에 const 를 사용하면 포인터가 가리키는 변수의 값을 변경할 수 없습니다. (간접 참조연산자를 사용할 수 없다)
* const 메소드는 무엇인가요?
아래의 코드에서 const 는 () 다음과 { 중괄호 시작 사이에 위치합니다. 이렇게 const 를 걸어놓으면 클래스의 멤버변수의 변경을 하지 못합니다. 주석처리한 부분은 멤버변수를 변경하는 코드인데 const 메소드에서는 사용할 수 없습니다.
* const 메소드를 왜 사용하나요?
const 한정자를 사용해서 메소드에서 멤버변수의 값을 변경할 수 없도록 바꾸면 디버깅 할 때 추적이 수월합니다. const 메소드에서 멤버 변수를 변경하지 않았다는 사실을 알 수 있기 때문이죠. 물론 멤버변수를 변경할 필요가 없는 경우에 사용합니다. 위의 메소드는 단순한 getter 입니다. private 에 있는 멤버의 값을 리턴하는 것이 주요 기능이기 때문에 const 를 사용해도 됩니다.
이름을 getter 로 지었다고 하더라도 멤버 변수를 변경할 가능성은 항상 있습니다. 유지보수가 잘되는 코드를 만들기 위해서 const 를 붙이는 것은 좋은 습관입니다.
const 객체와 const 포인터에 대하여 알아볼 시간입니다.
MyPosition 클래스로 테스트를 해봅니다. 아래의 클래스를 new 키워드로 생성하여 const 한정자를 적용시킵니다.
▶ const 객체에 포인터를 선언하면 const 메소드만 호출할 수 있습니다.
▶ 객체에 const 포인터를 선언하면 다른 객체를 가리킬 수 없습니다.
const 객체 포인터 등의 용어 때문에 헷갈리기 쉽습니다.
아래와 같이 세개의 객체를 힙 메모리에 생성합니다. const 가 붙어있는 위치에 주목할 필요가 있습니다.
▶ 첫번째 객체 ptrPos는 제한이 없습니다.
▶ 두번째 객체 ptrConstPos 는 const 객체에 포인터를 선언합니다. const 메소드만 사용가능합니다.
▶ 세번째 객체 prtConstPtr 은 객체에 const 포인터를 선언합니다. 다른 객체를 가리킬 수 없습니다.
* 결과를 확인할 수 있는 출력코드를 넣어 둡니다.
아래 코드를 보면 첫번째 객체에는 아무 제한이 없이 setter를 사용해서 멤버값을 변경합니다.
둘째 객체는 const가 아닌 setter 로 멤버변수를 변경할 수 없습니다. const인 getter 를 호출할 수는 있습니다.
세번째 객체는 const 포인터 즉 포인터가 상수입니다. 다른 객체로 바꿀 수 없죠.
위와 같은 결과를 확인할 수 있습니다.
const 라는 한정자를 그냥 상수를 만들기 위해 사용할 때는 몰랐는데 이렇게 사용해 보면 멀쩡히 있던 객체가 한층 복잡해지는 것이 보입니다. 여기까지도 충분히 복잡하지만 const 의 사용법은 이것이 다는 아닙니다. 다들 어려워 하는 부분이기 때문에 처음에 이해가 안되도 너무 걱정할 필요는 없습니다.
교재나 온라인의 설명들을 좀 더 읽어 보고 직접 연습을 해보는 방법이 좋습니다.
* 예제 코드
#include <iostream>
using namespace std;
#define Line cout <<"\n-----------------------------\n"
class MyPosition {
public:
MyPosition();
~MyPosition();
void setXPos(int x) { this->xPos = x; }
int getXPos() const {
// const 한정자는 멤버변수의 값을 변경할 수 없다.
// this->xPos = 19;
return this->xPos;
}
void setYPos(int y) { this->yPos = y; }
int getYPos() const { return this->yPos; }
private:
int xPos;
int yPos;
};
MyPosition::MyPosition()
{
xPos = 0;
yPos = 0;
}
MyPosition::~MyPosition()
{}
int main()
{
MyPosition* ptrPos = new MyPosition;
const MyPosition* ptrConstPos = new MyPosition;
MyPosition* const ptrConstPtr = new MyPosition;
Line;
cout << " ptrPos x : " << ptrPos->getXPos() << endl;
cout << " ptrPos y : " << ptrPos->getYPos() << endl;
cout << " ptrConstPos x : " << ptrConstPos->getXPos() << endl;
cout << " ptrConstPos y : " << ptrConstPos->getYPos() << endl;
cout << " ptrConstPtr x : " << ptrConstPtr->getXPos() << endl;
cout << " ptrConstPtr y : " << ptrConstPtr->getYPos() << endl;
ptrPos->setXPos(17);
ptrPos->setYPos(22);
// const 메소드에만 접근할 수 있다.
// ptrConstPos->setXPos(23);
// ptrConstPos->setYPos(99);
// 포인터 변수를 변경하는 것은 가능
ptrConstPos = ptrPos;
ptrConstPtr->setXPos(35);
ptrConstPtr->setYPos(42);
// 상수 포인터 가리키는 주소는 고정
// ptrConstPtr = ptrPos;
Line;
cout << " ptrPos x : " << ptrPos->getXPos() << endl;
cout << " ptrPos y : " << ptrPos->getYPos() << endl;
cout << " ptrConstPos x : " << ptrConstPos->getXPos() << endl;
cout << " ptrConstPos y : " << ptrConstPos->getYPos() << endl;
cout << " ptrConstPtr x : " << ptrConstPtr->getXPos() << endl;
cout << " ptrConstPtr y : " << ptrConstPtr->getYPos() << endl;
return 0;
}