C++/Syntax 2021. 3. 10. 21:01

상수 (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