ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • #define cosnt 상수변수로 바꾸기! operator[], const static, 클래스내 const, define 매크로
    @ 16. 1 ~ 17. 1/Effective C++ 2015. 12. 3. 21:02

    const 키워드는 팔방미인이라는데..

    1. 클래스 바깥에서는 전역 혹은 네임스페이스 유효범위의 상수를 선언(정의)하는데 쓰고

    const int a = 10; //헤더 파일 상단에..const 안붙이면 이곳저곳 헤더를 포함할때 난리남

    2. static으로 선언한 객체에도 const을 쓸 수 있고

    static const 이든 const static이든 똑같다

    3. 포인터에는 포인터 자체를 또는 포인터가 가리키는 데이터를 상수로 지정할 수 있다.

    int* const ptr 또는 const int* ptr 둘차이는 *을 기준으로 보는데..

    const int* ptr는 *기준왼쪽에 const이므로 포인터 가리키는 값 자체가 상수 /값변경불가능 주소변경가능

    int* const ptr는 *기준 오른쪽에 const이므로 포인터 자체가 상수로 된다. /주소변경불가 값변경가능

    일반변수는 const int 든 int const 든 다 똑같다.

     

    STL에서는 반복자를 const하는것은 T* const와 같다.

    const iterator iter 일 경우..iter로 주소이동은 불가하다..값 변경은 가능한데

    만약 주소이동은 가능한데 값 변경을 막고 싶다면 반복자를 const_iterator iter로 선언해야한다.

     

    그리고 함수에서 const

    반환값이 const라면 반환값에 대해서 변경을 못한다.

    매개변수라면 const타입의 지역객체와 특성이 같고

    함수뒤에 const가 붙는건 해당 멤버 함수가 상수 객체에 대해서만 호출된다.

    (비상수 객체도 호출가능, 상수 객체는 const밖에 호출못한다고)

    그리고 const여부로 함수 오버로딩이 가능함.

     


    operator[]에서 기본 타입을 반환할때 반환값을 수정하는일은 절대로 있을 수 없다. 컴파일 에러발생

    class A에

    int operator[](int num) 이런식으로 있을떄

    A a;

    a[10] = 100; 이런식으로 안된다..

    int&참조형으로 되어야지 수정이 된다.(물론 반환값이 참조형이니 주의해야할건 주의하고..지역변수는 안된다는 등등..)

    또는 이게 설령된다고 해도 값에 의한 반환을 수행하기 때문에 사본에 수정이다. 목적하고 맞지 않음

     

     


     

     

    const 사용시(#define A 1 이런건 const int A = 1; 이렇게 하는편이 낫다)

    포인터일때는

    포인터가 가리키는 대상까지 const로 선언하는 것이 보통이다.

    const char* name = "test"; 가 아니라

    const char* const name = "test"; 이다

    //이렇게 안하면 포인터로 전역변수 설정이 안됨 LNK02005 오류 발생(중복정의)

    왜냐면 name이 가리키는 주소까지 const을 하지 않으면 중간에 값이 바뀔 수 있다.

    name = "baba"; //name이 새로운 baba의 주소를 가리킨다.

    name[1] = "b"; //이건  const char* name = "test"; 할때 방지가 된다.

     


    const static과 static const는 같다

    클래스 내에서 const static 정수계열(bool char int 등..)만 초기화할 있다.

    const static double a = 3; 클래스 내에서 불가능. (외부에서는 가능)

    사용자 정의형을 메모리에 할당할때 실수는 최적화하기가 애매하다

    const static : 객체를 생성하지 않아도 클래스 지역내에서 사용할 있는 상수.

    클래스 내부에 선언된 static 변수이므로 클래스 지역 내에서만 사용할 있는 정적 변수이고,

    프로그램이 시작할때 생성되었으므로 하나만 존재한다.

    상수이므로 중간에 값을 변경할 없다.

    일반적인 클래스 const const static 차이점)

    하나만 존재하며, 객체가 생성되지 않아도 사용가능한게 const static.

    객체마다 존재하며, 객체가 생성되지 않으면 사용불가능한게 const.


     

    클래스 멤버에 static const int num이 있다고 치자..(정적멤버상수)

    (정적멤버일 경우 선언과 동시 초기화가 안됨 . static int num)

    이때 num을 초기화하는 방법은 2가지가 있다.

    첫번째는 헤더파일에 선언과 동시에 초기화

    class A

    {

    static const int num = 10;

    }

    이런게 있고

    두번째는 헤더파일에 선언하고 정의는 소스파일에서 하는것

    class A

    {

    static const int num;

    }

    소스파일에

    const int A::num  = 10; //static은 소스파일에서 생략해야함.

    이런식인데 문제는 A클래스내에 멤버변수가 배열로 있는데 그 크기가 num으로 되어있을때 문제가 발생한다.

     

    class A

    {

    static const int num = 10;

    int Array[num];

    }

    이럴때..첫번째 방법에는 문제가 없으나 두번째 방법에는 컴파일 에러가 int array[num]에서 발생한다.

    이유는 간단하다. 컴파일러는 컴파일 과정에서 이 배열의 크기를 알아야 하기 때문이다.(소스파일 이전에 알아야 한다는것.)

    그래서 첫번째 처럼 해야하고..

    그리고 정적멤버상수가 아닌 상수멤버가 있을 경우..(const int num)

    당연히 헤더에서 초기화가 안되고, 기본생성자를 사용자가 반드시 정의해줘야 한다.(디폴트 생성자일 경우 에러발생) 그 생성자에서 멤버초기화 리스트를 이용해서 상수멤버를 초기화해야한다. 당연히 그 상수멤버로 위에 배열의 크기를 잡으면 똑같이 당연히 안된다.

     

    두번째 방법의 해결책으로 첫번째 방법도 있지만 나열자 둔갑술이란게 있다.

    num자체를

    enum { num = 10 }; 으로 enum으로 선언해버리면 가능해진다. 그 이유는 나열자 타입의 값은 int가 놓일 곳에도 쓰일 수 있다는 것에서 출발한다.

     


    #define CALL_WITH_MAX(a,b) ((a) > (b) ? (a) : (b))

    매크로 작성시에는 본문에 들어 있는 인자마다 반드시 괄호를 씌워줘야한다. 안그러면 골치아픈일이 발생한다.

    #define문은 반드시 한 행으로만 작성해야 한다. 여러 행으로 된 매크로 함수를 정의하려면 각 행의 맨 끝에 \를 써준다.

     cout << CALL_WITH(++a,b) << endl; 이렇게 한다면

    a는 몇번 증가하겠는가?? 총 2번이다. 이유는

    ++a가 매크로 함수에서는 ((++a) > (b) ? (++a) : (b)) 이렇게 두번되기 때문에..a는 7이 나온다

    그럼 저 위에 이어서

     cout << CALL_WITH(++a,b+10) << endl; 이렇게 하면 a는 몇번 증가하는가?

    1번이다. 이유는..

    ((++a) > (b+10) > (++a) : (b+10)) 이렇게 되는데..

    a가 1증가된 8하고 b가 10이 더해진 10하고 비교해서 b+10이 더 크게 되어 뒤에 ++a는 안되므로 한번 증가가 된다..

    이런 어처구니 없는 매크로 함수 대신에 c++에서는

    인라인 함수에 대한 템플릿을 준비하면 된다.

    template<typename T>
    inline T& CallWithMax(T& a, T& b)
    {
     return a > b ? a : b;
    }
    이런식으로 하면

     int a = 5;
     int b = 0;

     int num = 0;
     num = CallWithMax(++a, b);
     num = CallWithMax(++a, b);
     cout << num << endl; //7 출력

    정상적으로 작동이 된다.

Designed by Tistory.