본문 바로가기
  • hazard_dev@__
  • hazard_dev@__
C++

[C++] static, const, explicit 제대로 알고 사용하기![2]

by Hazard3_o00sung 2020. 12. 19.
728x90

강력한 언어, C++입니다

Efficient Programming in C++

저번 Static설명에 이어서 설명을 시작하도록 하겠습니다. 만약, static글 읽어보지 못하신 분은 아래 링크 타고 들어가셔서 정적 변수에 관한 내용을 읽고 오시는 것을 추천드립니다.

hazarddev.tistory.com/53

 

[C++] static, const, explicit 제대로 알고 사용하기![1]

Powerful Language C++ C++에서 static, const, explicit이라는 생소할 수도 있고 생소하지 않을 수도 있는 키워드가 존재합니다. 하지만, 뭐 무조건 이걸 써야 한다 이런 개념은 아니지만, 위와 같은 키워드를

hazarddev.tistory.com

"Constant"

우린 이미 영단어로써 이 뜻을 알고 있습니다. 상수라는 뜻이라는 건 모두가 알지 않을까 생각합니다. 상수는 한번 정의되면 C/C++에서는 수정을 절대 절대 할 수 없습니다. 하려고 한다면, 컴파일러 레벨에서 분명한 거부 사인을 프로그래머에게 전달하기 때문입니다. 물론 다른 언어에서도 const가 있으나, 저희가 알고자 하는 것은 C++에서의 const죠! 여하튼 프로그램에서 고정된 변수의 값입니다. 다양한 상수 변수를 생각할 수 있습니다. int, double, long, float, short, char 등 많은 유형의 상수 타입 변수를 생성할 수 있습니다. 그러니까 const int argv = 10; 이나 const char argv = "hello"; 등 많은 방식으로 선언할 수 있으며, 리터럴 형태로 말하기도 합니다. 그렇다면 예제를 통해서 알아보도록 하겠습니다.

 

1
2
3
4
5
6
7
8
9
10
int
main()
{
    const int num1 = 10;
    const int num2 = 20;
    cout << num1 + 1 << endl;
    cout << num1 + num2 << endl;
    //num1 = 20; <--- can't assign
    return 0;
}
cs

 

보시다시피, const키워드를 사용해서 선언한 변수 같은 경우는 새로운 대입이 불가능하다는 것을 알 수 있습니다. 컴파일러레벨에서 막기 때문에 이는 컴파일 자체가 불가능합니다. 그렇다면 함수 및 클래스에서의 const를 보도록 하겠습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Foo{
    private:
        int var;
    public:
        Foo(){var = 10;}
        void show() const;
        void changeVal() const;
};
 
void Foo::changeVal() const{
    // var = 12; <--- can't assign new value 
    //member function is const function so,
    //can't change member variables
}
 
void Foo::show() const {
    cout << var << endl;
}
 
int
main()
{
    Foo foo;
    foo.show();
    return 0;
}
cs

 

두개의 멤버 함수가 선언되었다는 것을 알 수 있습니다. 하나는 var를 출력하는 함수와 var의 값을 변경하는 함수입니다. 하지만 하나는 동작하지만 하나는 컴파일 영역에서 거부된다는 것을 알 수 있습니다. 이유로는 함수에 const가 붙게 되면, 선언된 함수 영역에서 값을 변경하지 않겠다는 의미이기 때문입니다. 값을 변경하지 않는 선에선 단순 대입 복사 정도는 가능하지만, 값을 새로 할당하거나 증감 연산은 불가능합니다.

 

1
2
3
4
5
6
#define MAX 1000
 
void changeVal2(){
    //MAX += 2; <--- define preprocessing keyword variables
    //can't assign new value or binary operand
}
cs

 

또한 define 전처리기 문으로 작성된 값 또한 const변수와 같이 고정된 값입니다. 컴파일러는 소스파일에서 식별자에 대한 토큰 문자열을 대체합니다. 그러니까 컴파일 영역에서 메모리를 할당하는 것이 아닌 define 매크로로 정의된 매개변수를 컴파일러가 다른 영역(함수 혹은 클래스) 등에서 만났을 때 그때그때 값을 할당해주기 때문입니다. 그렇기 때문에 const변수는 메모리를 확인 가능하나 define은 확인할 수 없다는 차별점을 가지고 있습니다.

 

Static const var

그렇다면 저번 시간에 설명드린 static키워드와 const키워드를 동시에 사용하는 예제 또한 보도록 하겠습니다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
static const int foo = 1000;
class mini{
    static const int bar = 100;
    public:
        mini(){}
        void op()const{
            int temp = 10;
            while (temp != 0){
                cout << bar - temp << endl;
                temp--;
            }
        }
};
 
int
main()
{
    //foo = 12; <--- can't assign new value
    cout << foo << endl;
    mini m;
    m.op();
    return 0;
}
cs

 

값을 새로 할당하는 것은 안되지만 아무 값도 반환하지 않고, 변경하지 않는 이항 연산은 가능하다는 것을 알 수 있습니다. 정적 변수를 저번 시간 때 설명드렸듯이, 객체가 생성되기 전 컴파일러는 이미 정적 변수에 대한 메모리를 할당합니다. 자세한 설명은 위 링크 static에 대한 설명을 보는 것을 추천드립니다. 여하튼 그렇기 때문에 아래 연산들이 가능한 것입니다. 정리드리자면, static const var = 10;은 불변 타입의 정적 변수 var의 값 10 이렇게 고정된다고 이해를 하는 편이 가장 이상적이라고 생각합니다. 

 

 

Explicit

explicit는 말 그대로 명시적 즉, 명시적인 ~다라는 개념의 키워드입니다. 그렇기 때문에 개발자가 선언한 객체의 형 변화를 막는 데 사용하는 키워드이며, 형 변환을 강제로 제한합니다. 이렇게 설명하면 감이 잘 오지 않기 때문에 아래 코드를 보도록 하겠습니다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Vector{
    private:
        double x, y;
    public:
        Vector(double i=0.0double j=0.0):x(i),y(j){}
        void show () const{
            cout << "x val : " << x << " " << "y val : " << y << endl;
        }
        bool operator == (Vector vec){
            return vec.x == x && vec.y == y ? true : false;
        }
};
 
int
main()
{
    Vector vector(3.00.0);
    if (vector == 3.0){
        cout << "It's same value" << endl;
    }else{
        cout << "Diff" << endl;
    }
    return 0;
}
cs

 

조금 어려운 부분이 존재할 수 있으나 잘 보시기 바랍니다. Vector객체는 3.0과 0.0의 값으로 초기화되었다는 것을 알 수 있습니다. 그리고 생성자에서 명시적인 형변환을 진행하지 않았기 때문에 if 조건문에서의 vector == 3.0은 마치 vector == (Vector) 3.0과 동일하게 동작되었다는 뜻입니다. 이는 프로그램의 수명과 로직에 치명적인 손상을 줄 수 있다는 점을 간과해선 안됩니다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Vector{
    private:
        double x, y;
    public:
        explicit Vector(double i=0.0double j=0.0):x(i),y(j){}
        void show () const{
            cout << "x val : " << x << " " << "y val : " << y << endl;
        }
        bool operator == (Vector vec){
            return vec.x == x && vec.y == y ? true : false;
        }
};
 
int
main()
{
    Vector vector(3.00.0);
    if (vector == 3.0){ // invalid operands to binary expression 
    //because Vector and double is different type object
        cout << "It's same value" << endl;
    }else{
        cout << "Diff" << endl;
    }
    return 0;
}
cs

같은 코드라고 생각될 수 있으나 자세히 보면 완전히 다릅니다. Vector Constructor는 explicit키워드를 사용해서 선언되었기 때문에 명시적으로 자신만의 타입을 가집니다. 그렇기 때문에 컴파일 시도 시 아래와 같은 오류를 얻습니다. vector와 double은 다른 타입 객체니까 컴파일할 수 없다는 겁니다. 

1
2
3
4
5
6
if (vector == (Vector)3.0){ // invalid operands to binary expression 
    //because Vector and double is different type object
        cout << "It's same value" << endl;
    }else{
        cout << "Diff" << endl;
    }
cs

하지만 아래와 같이 형 변환을 명시적으로 해주게 되면 임시적으로 이항 연산 컨디션 내에서는 Vector객체로 생성자를 통해 생성되어 연산자 오버로드 멤버 함수와 비교되어 값이 출력되게 됩니다!

 

조금 어려울 수 있으나, 천천히 코드를 작성하고 읽어보시면 모두 이해가 될 내용이라고  생각됩니다!!

 

궁금한 점, 피드백, 문의 등은 아래 댓글창에 남겨주시면 감사하겠습니다!!

 

글 잘 보셨다면 공감과 궁금하신 분들께도 보여주시면 감사하겠습니다!!!

 

그럼 20000😜😜😜😜😜😜😜😜

728x90

댓글