상수 (Constant)
Literal constant
숫자, 문자 등 메모리에 존재하지 않아도 사용 가능한 값
Binary Literal
C++14
0b1011'1111'1010
Symbolic constant
Compile Time constant
컴파일할 때 값이 결정되는 상수
constexpr
C++11
컴파일 타임에 값이 결정되는 상수에만 사용 가능한 키워드이다.
Runtime constant
- 런타임에 값이 결정되는 상수
매크로
C 스타일에서는 상수를 매크로로 정의했지만, C++에서는 그렇게 사용하지 않는다고 한다.
이유
디버깅이 귀찮아진다.
적용 범위가 너무 넓다.
대신에 함수 내에서
const
형식으로 작성하는 것이 일반적이라고 한다.
const_cast
const
로 지정한 상수의 값을 변경할 때 사용한다.#include <iostream> int main() { using namespace std; const double gravity{ 9.8 }; double* temp = const_cast<double*>(&gravity); cout << &gravity << ' ' << temp << endl; *temp = 123.0; cout << &gravity << ' ' << temp << endl; cout << gravity << ' ' << *temp << endl; } /* stdout stderr 000DDFC84 00DDFC84 00DDFC84 00DDFC84 9.8 123 */
같은 주소를 사용하는데 다른 값이 나온다...
memcpy
함수를 사용해도 변하지 않는다.#include <iostream> int main() { using namespace std; const double gravity{ 9.8 }; cout << gravity << endl; // 9.8 const double temp = 1024.0; memcpy(const_cast<double*>(&gravity), &temp, sizeof(double)); cout << gravity << endl; // 9.8 } /* stdout stderr 9.8 9.8 */
이렇게 사용하지 않는게 좋을 것 같다.
클래스에서의 const
클래스를 const
로 인스턴스화 (instanciation)
멤버 함수를 정의할 때, 값을 변경하지 않는 함수면 컴파일러가 알 수 있도록 함수 정의 시
const
키워드를 붙이는게 좋다.멤버 변수들을 수정할 수 없다. 모두
const
취급하는 것이다.int getValue() const { return value_; }
함수 파라미터에 const
와 레퍼런스를 같이 붙이는 이유
다음 예제에서
print
함수의 파라미터는 복사 생성자를 호출한다.#include <iostream> class Something { int value_ = 0; public: Something() { std::cout << "Constructor\n"; } int getValue() const { return value_; } }; void print(Something s) { std::cout << &s << std::endl; std::cout << s.getValue() << std::endl; } int main() { const Something s; std::cout << &s << std::endl; print(s); } /* stdout Constructor 012FFB9C 012FFAC8 0 */
"Constructor" 메시지가 한 번만 출력된 것을 볼 수 있다.
- 위에 정의된 생성자가 아닌, 기본 복사 생성자를 호출했기 때문이다.
이렇게 복사하는건 오버헤드가 크기 때문에 다음과 같이 원본으로 가져오는게 일반적이다.
#include <iostream> class Something { int value_ = 0; public: Something() { std::cout << "Constructor\n"; } int getValue() const { return value_; } }; void print(const Something& s) { std::cout << &s << std::endl; std::cout << s.getValue() << std::endl; } int main() { const Something s; std::cout << &s << std::endl; print(s); } /* stdout Constructor 00AFFB78 00AFFB78 0 */
const
키워드 유무에 따라 오버로딩이 다르게 적용된다.원래 같은 파라미터를 갖는 같은 이름의 함수는 두 개 이상 정의할 수 없으나,
const
가 붙는 함수는 다른 함수 취급한다.#include <iostream> class Something { int value_ = 0; public: const int& getValue() const { std::cout << "const version : " << value_ << '\n'; return value_; } int& getValue() { std::cout << "non-const version : " << value_ << '\n'; return value_; } }; int main() { Something s1; const Something s2; s2.getValue(); s1.getValue() = 100; s1.getValue(); } /* stdout const version : 0 non-const version : 0 non-const version : 100 */
다음과 같이
const
를 빼고getValue
함수를 작성하면 오버로딩 오류가 발생한다.public: const int& getValue() // 여기 const가 없으면 오류 { std::cout << "const version : " << value_ << '\n'; return value_; } int& getValue() { std::cout << "non-const version : " << value_ << '\n'; return value_; }
error C2556: 'int &Something::getValue(void)': overloaded function differs only by return type from 'const int &Something::getValue(void)'
다음과 같이 반환 값에
const
가 없어도 오류가 발생한다.int& getValue() const { std::cout << "const version : " << value_ << '\n'; return value_; }
error C2440: 'return': cannot convert from 'const int' to 'int &'
int& getValue() const
에서 오른쪽const
에 의해 내부 변수 값들이const
취급된다. (여기서는const int
)그런데 반환 값은
int&
형태의 레퍼런스이므로 자료형이 맞지 않아서 발생하는 오류이다.반환 자료형을 레퍼런스 없이
int
로만 쓰면 오류는 없지만, 앞에도const
를 붙여주는게 맞는 것 같다.
'C++ > Syntax' 카테고리의 다른 글
C++ 쉼표 연산자 (Comma Operator) (0) | 2021.03.10 |
---|---|
C++ 산술 연산자 (Arithmetic Operator) (0) | 2021.03.10 |
C++ 형 변환 (Type Casting) (0) | 2021.03.09 |
C++ Boolean (0) | 2021.03.09 |
C++ 소수점 (Decimal Point) (0) | 2021.03.09 |