effective c++ & c++

ch01-03. const 들이대기 2

공대녀J 2022. 8. 31. 21:33

상수 멤버 함수

해당 멤버 함수가 상수 객체에 의해 호출될 함수임을 의미.

 

상수 멤버 함수의 의미

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 선언으로 인한 형의 불일치가 발생해서 인자의 전달이 불가능한 경우에 유용하게 사용된다.