ch01-03. const 들이대기 2
상수 멤버 함수
해당 멤버 함수가 상수 객체에 의해 호출될 함수임을 의미.
상수 멤버 함수의 의미
1. 물리적 상수성(=비트 수준의 상수성)
2. 논리적 상수성
물리적 상수성(=비트 수준의 상수성)
어떤 멤버 함수가 그 객체의 어떤 데이터 멤버도 건드리지 않아야 정적 멤버 함수임을 인정.
컴파일러는 테이터 멤버에 대입 연산의 수행 여부만 파악하면 된다.
class CTextBlock
{
private:
char* pText;
public:
char& operator(size_t pos) const
{
return pText[pos];
}
};
...
const CTextBlock cctb("Hello");
char *pc = &cctb[0];
*pc = 'J'; // 물리적 상수성은 만족하지만 멤버함수 반환형이 const가 아니여서 참조를 통한 값 변경 가능.
논리적 상수성
상수 멤버 함수라 해서 객체의 한 비트도 수정할 수 없는 것이 아니라, 일부 몇 비트 정도는 바꿀 수 있되
그것을 사용자측에서 알아채지 못하게 한다면 상수 멤버 자격이 있음을 의미.
mutable 키워드를 통해 구현 가능하다.
class CTextBlock
{
private:
char *pText;
mutable size_t textLength; //pText의 길이값이기 때문에 사용자가 이를 직접 수정할 수 없게 해야함.
mutable bool lengthIsValid;
public:
size_t length() const;
};
size_t CTextBlock::length() const
{
if(!lengthIsValid)
{
textLength = strlen(pText);
lengthIsValid = true;
}
return textLength;
}
** mutable 키워드는 const가 붙은 구조체나 클래스,멤버 함수에서 특정 멤버 변수의 수정을 허용하는 키워드이다.
mutable int a;
int mutable b;
멤버 변수의 자료형 앞,뒤에 붙는 게 동일한 의미이고 가능하다.
상수 멤버 함수가 중요한 이유
1. 해당 멤버 함수로 구성된 클래스의 객체를 변경할 수 있는 함수를 구분.
2. 상수 객체를 사용 가능하게 함. (상수 객체는 상수 멤버 함수만 호출 가능하기 때문이다.)
** 상수 객체가 생성되는 경우에는
1. 상수 객체에 대한 포인터로 객체가 전달되는 경우
2. 상수 객체에 대한 참조자로 객체가 전달되는 경우 -> 프로그램의 실행 성능을 높이는 핵심 기법 중 하나.
두가지가 있다.
void print(const TextBlock& tb) // 상수 객체로 사용된 tb
{
cout<<tb[0];
...
}
const의 있고 없고의 차이만으로 멤버 함수의 오버로딩이 가능하다.
class TextBlock
{
private:
string text;
public:
const char& operator[](size_t pos) const
{
return text[pos];
}
char& operator[](size_t pos)
{
return text[pos];
}
};
상수 멤버 함수와 비상수 멤버함수가 const를 제외한 모든 기능이 동일할 경우
비상수 버전의 멤버함수에서 상수 멤버 함수를 호출하도록 만든다.
(상수 멤버 함수에서 비상수 멤버 함수를 호출하는 것은 안정성에 문제가 된다.)
class TextBlock
{
public:
const char& operator[](size_t pos) const
{
...
return text[pos];
}
char& operator[](size_t pos)
{
return
const_cast<char&> //상수 operator[]의 반환값에서 const를 떼어내는 캐스팅
(
static_cast<const TextBlock&>(*this)[pos] //*this에 const를 붙이는 캐스팅
);
}
...
};
# const_cast와 static_cast 에 대해 복습해보자.
- 형 변환 연산자
1. static_cast 연산자
- static_cast <T> (변환의 대상) 형태로 사용.
- T에는 객체의 포인터 또는 참조형이 와야한다.
- 유도 클래스의 포인터 및 참조형 데이터를 기초 클래스의 포인터 및 참조형 데이터로 형 변환 가능.
- 기초 클래스의 포인터 및 참조형 데이터를 유도 클래스의 포인터 및 참조형 데이터로 형 변환 가능.
class Car
{
...
}
class Truck : public Car
{
...
}
int main()
{
Car* pcar2=new Car(120);
Truck* ptruck2=static_cast<Truck*>(pcar2);
}
- 기본 자료형 데이터 간의 형 변환에도 사용 된다.
- 상수 객체 -> 비상수 객체로의 변환을 허용하지 않는다.
2. const_cast 연산자
- const의 성향을 삭제하는 형 변환을 목적으로 한다.
- const_cast<T>(expr)
- const 선언으로 인한 형의 불일치가 발생해서 인자의 전달이 불가능한 경우에 유용하게 사용된다.