낌새만 보이면 const를 들이대자!
-> 어떤 값이 불변이어야 한다는 제작자의 의도를 컴파일러 및 다른 프로그래머와 나눌 수 있는 수단.
1. const는 전역 혹은 네임스페이스 유효범위 내의 상수를 선언하는 데 사용할 수 있다.
--> const int Width = 10;
2. 파일, 함수, 블록 유효범위에서 static으로 선언한 변수에도 사용할 수 있다.
--> void SetX(){
static const int count = 1;
}
3. 클래스 내부의 데이터 멤버
--> class AAA{
private:
const int count;
static const int Size = 10; --> 객체 내부의 정적 멤버도 당연 적용할 수 있다.
}
4. 포인터
1. const int* aptr; --> 포인터로 데이터 조작을 하지 않겠다. 가리키는 대상을 상수화 --> 가리키는 대상은 바꿀 수 있음.
2. int* const aptr; --> 하나만 가리키겠다. 포인터를 상수화 --> 데이터 조작은 가능
3. const int* const aptr; --> 가리키는 대상도 바꾸지 못할 뿐더러, 포인터를 통한 데이터 조작까지 허용하지 않겠다.
5. STL의 반복자
STL의 반복자 즉 iterator는 포인터를 본뜬 것이기 때문에, 기본 동작원리가 T* 포인터와 흡사하다.
반복자를 const로 선언하는 것은 T* const 와 같다. --> 즉 포인터를 상수화 하겠다는 말이다.
그렇다면 가리키는 대상을 상수화 하려면 어떻게 해야 할까? --> const_iterator를 쓰면 const T* 와 같이 동작한다.
아래 예제를 보자.
vector<int> vec;
1. const vector<int>::iterator iter = vec.begin(); --> iter는 T* const 처럼 동작. 즉 위의 2번과 같이 포인터를 상수화한 형태
*iter = 10; --> 따라서 데이터 조작은 가능하다.
++iter; --> 하지만 가리키는 대상을 바꾸는 것은 불가능!
2. vector<int>::const_iterator cIter = vec.begin(); --> cIter는 const T* 처럼 동작. 즉 위의 1번과 같이 가리키는 대상을 상수화한 형태
*cIter = 10; --> 따라서 데이터 조작이 불가능하다.
++cIter; --> 가리키는 대상을 바꾸는 것은 가능하다!
6. 함수
ex)
const AAA operator(const AAA& lhs, const AAA& rhs);
AAA a, b, c;
1. (a*b) = c;
2. if(a*b = c)
---> 1,2번과 같은어처구니 없는 코드를 예방할 수 있다.
상수 멤버 함수
1. 이 함수를 통해서 멤버 변수의 값이 변경되는 것을 허용하지 않겠다!!
2. 상수화된 함수는 상수화되지 않은 함수의 호출을 허용하지 않는다. --> 상수화 되지 않은 함수 내에서 데이터 조작의 가능성이 있기 때문
3. 또한 멤버 변수의 포인터를 리턴하는 것도 허용하지 않는다. --> 반환된 포인터로 조작의 가능성이 있기 때문
--> 따라서 const int* GetPtr () const --> 이런 형식으로 진행하도록 하자. 4항목의 2번 참고
4. const 키워드에 유무에 따라 함수 오버로딩이 가능하다.
//////////////////// 멤버 함수
void show() const; 1번
void show(); 2번
//////////////////// 객체 선언
AAA aaa;
const AAA bbb;
aaa. show(); --> 비상수 객체 --> 두 개의 show()를 모두 불러올 수 있다. -->우선순위가 높은 비상수 함수를 불러온다. 2번
bbb.show(); --> 상수 객체 --> 오직 상수 함수만을 불러올 수 있다. 1번
5. 클래스의 인터페이스 향상 --> 멤버 변수를 조작할 수 있는 함수는 무엇이고, 조작할 수 없는 함수는 무엇인가? 를 알아야한다.
6. 상수 객체를 사용할 수 있게 된다. --> 객체 전달을 상수 객체에 대한 참조자로 진행하는 것 --> 복사손실 복사비용을 없애주어 코드 효율 UP
7. 상수 객체
1. 상수 멤버 함수만 불러올 수 있다.
실제 프로그래밍에서 상수 객체가 생기는 경우
1. 상수 객체에 대한 포인터 혹은
2.상수 객체에 대한 참조자로 객체가 전달될 때이다. (위의 6번 참고)
void print (const Player& cp){ ... }
참고)
const int& GetInt(int& a) { return a; }; 1번
int & GetInt(int& a) { return a; } 2번
1번의 경우
int a = 10;
int b = GetInt(a); --> 가능
int &b = GetInt(a) ---> 불가능. 데이터 조작의 위험성이 있다. 반환된 레퍼런스로 어떠한 데이터 조작도 할 수 없다.
2번의 경우 모두 가능.
Player& 리턴과
Player 리턴의 차이
--> 함수의 반환 타입이 객체의 참조형식일 경우 리턴된 객체가 그 자리에 반환되게 된다.
--> 참조형식이 아닐 경우 리턴된 객체의 복사본이 오게 된다.
const 키워드는 프로그램을 안정적으로 작성하는데 많은 도움을 준다.
기능적인 측면 말고도 오류를 쉽게 찾아낼 수 있다는 이점까지 줄 수 있다.
따라서 const 키워드는 가급적이면 많이 사용하도록 하자.
const에 대해 상당히 많은 내용이 정리되어 있다.
나름 쉽게 풀어쓴다고 썼지만 포스팅이 아직 어색하여
보기 썩 좋은 모양새는 아닌 듯 하다.
비트수준 상수성, 물리적 상수성 그리고 상수 비상수 멤버의
코드 중복현상을 피하는 방법에 대해서는 다음에 포스팅 하도록 하겠다.
'C++ 심화' 카테고리의 다른 글
[C++] 가상(virtual) 소멸자 (0) | 2016.12.18 |
---|---|
[C++] 컴파일러가 만들어낸 함수가 필요 없을 때 (0) | 2016.12.18 |
[C++] 생성자, 소멸자, 대입 연산자에 주의를 기울이자. (0) | 2016.12.15 |
[C++] 객체의 초기화 (0) | 2016.12.15 |
[C++] #define 대신 const, enum, inline를 쓰자. (0) | 2016.12.14 |