※ const

const가 붙은 객체는 외부 변경을 불가능하게 해주며 다방면으로 사용된다.

클래스 내부: 정적멤버, 비정적 데이터 멤버 모두 상수로 선언 가능

클래스 외부: 전역, namespace 유효범위의 상수를 선언, static 객체 등에도 const를 붙일 수 있다.

포인터: * 뒤에 const를 붙여 상수포인터로 하거나 * 앞에 const 포인터가 가리키는 데이터를 상수로 할 수 있고 const char* const p 처럼 상수포인터, 상수데이터로도 만들 수 있다.

 

const의 가장 강력한 용도함수 선언을 할 때이다.

포인터, 반복자와 [포인터반복자참조자]가 가리키는 객체, 함수의 반환값 매개변수, 지역변수는 물론 멤버함수, 함수전체 등 여러곳에서 사용될 수 있다.

 

이 함수 내에서는 멤버변수에 저장된 값을 변경하지 않겠다는 의미로

const 함수 내에서는 const가 아닌 함수의 호출이 제한된다.

const 참조자를 이용한다면 const 함수만 호출이 가능하다.

class Numclass{
private:
    int num;
public:
    int GetNum() const { return num; }
};

class NumberClass{
private:
    int number;
public:
    void initNum(const Numclass& num){
        number = num.GetNum();
    }
};

 

const 반환값은 안전성과 효율성의 증가, 에러돌발상황감소 등 여러 상황을 효과적으로 막을 수 있다.

class Rational { . . . };
const Rational operator* (const Rational& lhs, const Rational& rhs);

만약 상수객체로 되어있지 않으면 아래와 같은 상황에서 Error가 발생한다.

Rational a, b, c;
(a * b) = c;  // a*b의 결과에 operator= 을 호출한 것이 되어버린다.

 

const 멤버 함수해당멤버함수가 상수객체에 대해 호출될 함수라는 뜻으로 2가지의 중요성을 갖는다.

1. 클래스로 만들어진 객체를 변경가능한 함수와 가능하지 않은 함수 구분을 시켜준다.

2. 객체전달을 상수 객체에 대한 참조자로 진행하여 상수객체를 사용하기 위해 상수멤버함수를 준비한다.

const char& operator[] (std::size_t pos) const { return text[pos]; }

void print (const TextBlock& ctb){    // 상수객체 ctb
    cout << ctb[0];  //TextBlock::operator[]의 상수
}

 

그렇다면 어떤 멤버함수가 const라는 것은 무슨 의미일까?

1.비트수준 상수성(물리적 상수성): 어떤 멤버함수가 정적멤버를 제외한 어떤 데이터도 건드리지 않음
2.논리적 상수성: 일부 비트정도는 바꿀수 있되 그것을 사용자가 모르게만 하면 상수멤버 자격이 있음

Q. 상수멤버 및 비상수멤버 함수가 기능적으로 똑같게 구현되었다면?

A. 코드중복을 피하는것이 좋은데, 이때 비상수 버전이 상수버전을 호출하도록 해야한다.

 

 

※ const 멤버 변수와  const static 멤버변수의 초기화 차이.

- const 멤버 변수: initializer를 이용해 멤버변수(객체)를 초기화 해야 한다. 이로 인해 선언과 동시에 초기화 되는 Binary code가 생성 가능하다.

class Country {
private:
    const int KoreaNum;
public:
    Country(const int KoreaNum) : KoreaNum(KoreaNum){ }
};

- const static 멤버변수: 선언과 동시에 초기화가 가능하다.

const static int KoreaNum = 82; //Country class의 public멤버
cout << "국번" << Country::Korea;

 

 

 

 

 

 

※ constexpr (C++11)

기존의 const 보다 더 상수성에 충실하며 일반화된 상수표현식 (Generalized constant expression)을 사용할 수 있게 해줌.

변수, 함수, 생성자 함수에 대하여 일반화된 상수표현식을 통해 컴파일 타임에 평가도리 수 있도록 처리해주는 키워드이다.

C++17부터는 람다함수에서도 constexpr키워드의 사용이 가능해졌다.

 

§ 변수에서의 사용

const와 constexpr의 차이점

[const]: const변수의 초기화를 런타임까지 지연시킬 수 있다.

[constexpr]: 반드시 컴파일 타임에 초기화 되어있어야 한다.

따라서 초기화가 안되어있거나 상수가 아닌 값으로 초기화 시도하면 컴파일이 되지 않는다.

constexpr float x = 42.f;    // OK
constexpr float y { 108.f }; // OK
constexpr int i;             // error C2737: 'i': 'constexpr' 개체를 초기화해야 합니다. (uninitialized 'const i' [-fpermissive])
int j = 0;                   // error: 'int j' is not const
constexpr int k = j + 1;     // error C2131 : 식이 상수로 계산되지 않았습니다.(the value of 'j' is not usable in a constant expression)

 

 

 

§ 함수에서의 사용

constexpr을 함수반환값에 사용시 다음의 제약이 있다.

1. 함수에 constexpr을 붙일 때는 inline을 암시한다.
2. 즉, 컴파일타임에 평가하기에 inline함수들과 같이 컴파일 된다.

만약 constexr의 함수인자들이 constexpr규칙에 어긋나면 컴파일타임에 실행되지 못하고 런타임에 실행된다.

constexpr int factorial(int n) {
    // 지역 변수 없음, 하나의 반환문
    return n <= 1 ? 1 : (n * factorial(n - 1));
}

// C++11에서는 컴파일 에러 발생
// C++14부터 가능
constexpr int factorial(int n) {
    // 지역 변수
    int result = 0;

    // 여러 개의 반환문
    if (n <= 1)
        result = 1;
    else
        result = n * factorial(n - 1);

    return result;
}

 

 

 

 

 

 

 

 

 

+ Recent posts