Invisible Rover 's Blog :D ::

'const'에 해당되는 글 2건

  1. const 변수, 함수, 객체....... 2008/04/17
  2. const 제한자. (2) 2008/02/15

const 키워드를 붙이면 변수를 상수화 한다....  "상식"이 되어버렸지만 변수 이외에 포인터 , 맴버데이터 , 함수 ,객체까지 확장할경우 의미가 넓어진다. 하지만 진정한 const의 의미는 안정적인 프로그래밍 코드구현에 있다.

일단 기본 상식인 변수와 포인터 를 const화 시키는건 요약글로 묶어두고... ㅋ

const 포인터 변수 짬깐 들여다보기 ㅋㅋ


const키워드와 맴버데이터
기본적인 변수를 상수화 시키는것과 같은 이치다. 하지만 맴버데이터이니만큼 어떻게 초기화 시키는지쯤은 알고 넘어가야 하겟다.
작성법 : 일반 변수와 같이 const키워드를 앞에 붙여주면된다.
#include<iostream>

using std::cout;
using std::endl;

class test{
    const int num;

public:
    test(int _num){
        num = _num;
    }
    void print(){
        cout<<"num = "<<num<<endl;        
    }
};

int main(){
    test work(10);
    work.print();
    return 0;
}
객체를 생성함과 동시에 맴버데이터값을 초기화 하고있다. 하지만 const화된 데이터를 직접 초기화 할수는 없다.
그래서 나온것이 "이니셜라이져" 라고하는 초기자이다.


초기자를 사용하여 const화된 맴버데이터를 초기화 하는 올바른 test 클래스

class test{
    const int num;

public:
    test(int _num):num(_num){
    }
    void print(){
        cout<<"num = "<<num<<endl;        
    }
};

사용자 삽입 이미지





초기자는 함수의 몸체부분이 실행되기전에 먼저 실행된다.
그렇다면 왜 초기자를 사용해야할까? 클래스내부에서 초기화할순 없는건가?... 라고 생각하는 사람들이 많은데.... -ㅅ-; 구조체 내부에서 값을 초기화 할수있었나?? 불가능했다. 클래스또한 마찬가지이다.
그렇다면 왜 생성자에서 초기화 할까? 메모리구조상 객체를 찍어내는 순간 그 객체를 메모리공간에 올라가는데 이와 동시에 생성자를 호출한다. 하지만 초기자는 생성자 이전에 실행되기때문에 미리 맴버데이터를 초기화시켜줄수있게 되는것이다.

초기자의 사용방법 :  함수(자료형 매개변수) : const변수(매개변수) , ....{} 라고 적어주면된다.
ex)
class test{
    const int num;
    int x;
    int y;

public:
    test(int _num , int _x , int _y ):num(_num) , x(_x) , y(_y){
    }
    void print(){
        cout<<num<<x<<y<<endl;        
    }
};





const 키워드와 맴버함수
맴버함수의 상수화는 곳 그함수내에서는 데이터에 관한 어떤 조작도 할수없을 뿐더러 값조작의 기회조차 주지 않음을 의미한다.
작성법 : const 키워드를 함수 머리 뒷부분에 적어줌으로써 함수를 상수화 시키는면된다.

#include<iostream>

using std::cout;
using std::endl;

class test{
    int Notouch;

public:
    test():Notouch(10){   //변수(값)은 C++스타일의 초기화방법
    }
    void print() const{
        cout<<Notouch<<endl;
        Notouch++;    //컴파일 에러!!
    }
};

int main(){
    test work;
    work.print();
    return 0;
}

상수화된 맴버함수는 값 조작 권한을 잃는다.

아래 또하나의 코드를 통해 상수화된 두 함수간의 관계를 알수있다. 안봐도 되지만 본다면 ㅋㅋ

#include<iostream>

using std::cout;
using std::endl;

class test{
    int Notouch;

public:
    test():Notouch(10){
    }
    void print() const{
        cout<<Notouch<<endl;
        Notouch++;  //컴파일 에러!!
        print2();   //컴파일 에러!!
    }

    void print2(){
        cout<<Notouch<<endl;
    }
};

int main(){
    test work;
    work.print();
    return 0;
}

컴파일에러가 뜨는이유는 print2함수에서 맴버데이터를 조작할 가능성이 있기때문이다. 프로그래머가 보기에는 print2함수에선 아무 데이터 조작도 하지않지만 컴파일러는 그렇게까지 관대하지 못하기때문에 확실함을 요구하는 차원에서 에러를 띄워주는 것이다. 또하나의 이유는 값조작이며 위에서 언급했으므로 pass~

올바른 클래스
class test{
    int Notouch;

public:
    test():Notouch(10){
    }
    void print() const{
        cout<<Notouch<<endl;
        //Notouch++;
        print2();
    }
    void print2() const{
        cout<<Notouch<<endl;
    }
};

이를 토대로 const함수는 const함수만 호출이 가능함을 알수있다.




const 키워드와 객체
상수화된 변수처럼 사용하면된다. 상수화된 객체는 맴버데이터의 변경이 절대적으로 불가능해진다.
작성법 : const 클래스 객체;

#include<iostream>

using std::cout;
using std::endl;

class test{
    const int val;

public:
    test(int _val):val(_val){
    }

    void print() {        //컴파일 에러!!
        cout<<val<<endl;
    }
};

int main(){
    const test work(10);
    work.print();
    return 0;
}
상수화된 객체는 상수화된 함수만을 호출해야한다.
이유는 즉, 상수화의 의미를 이해하면되는데,,;  값조작을 허용치않는 객체에서 값 조작이 가능한 비 상수화 함수를 호출했다고 가정할경우 맴버데이터값이 변하게되는 원치않는 일이 발생할수있기 때문이다. 컴파일러는 이런 상황이 일어나지않을수 있음에도 불구하고 자비롭지못해 에러를 내뱉는다.

생성자도 함수인데 그럼 생성자도 const화 시킬수있나요? 그건 나도 잘모르겠지만 생성자를 상수화 시키는건 의미없는 행위같다. 생성자의 진정한 의미는 맴버데이터의 값을 조작하기 위함인데 그것마저 const화시킨다면...; 물론 초기자를 이용해서 값을 바꿀수도 있지만 쪕 -ㅅ-;;; 쫌 거지같은 const;;  아 .. 얘기가 딴대로 흘럿네.. 암튼!

여기서 또 오버로딩의 개념이 나오는데 상수화된 객체와 비 상수화된 객체가 맴버함수를 호출할때 인자값이 같을경우 어떻게 오버로딩을 하느냐?! ㅋㅋㅋ 바로 const키워드를 붙이느냐 안붙이느냐의 여부에따라 오버로딩이 되는거다.

함수의 오버로딩
#include<iostream>

using std::cout;
using std::endl;

class test{
    const int val;

public:
    test(int _val):val(_val){
    }

    void print() const{
        cout<<val<<endl;
    }

    void print(){
        cout<<val<<endl;
    }
};

int main(){
    const test work1(10);
    work1.print();

    test work2(20);
    work2.print();
    return 0;
}

사용자 삽입 이미지

댓글을 달아 주세요

상수를 기호 이름으로 나타내면 그 상수가 무엇을 의미하는 것인지 금방 알 수 있다.
상수를 기호화.... C언어에서 제한자를 배우지 않았? 던 거같은데 대신 치환자를 배웠다. #define 는 치환자와 매크로의 기능을 갖고있는데 치환자의 기능이 매우 강력하다. 하지만 const 제한자보다는 그 위력이 덜하다. 치환자를 이용하여 상수를 기호화하는것은 매우 효율적인 방법이다. 여러가지 상수가 동일한 의미의 값으로 되어있다면 치환자를 이용해서 상수를 기호화시킨후 상수대신 기호로써 표시하면 나중에 디버깅이라든지.. 혹은 다른 사람들이 코드를 들여볼때 훨씬 더 보기 쉬울것이다.

하지만 치환자에는 큰 단점이 있는데 바로 활동범위이다. #define는 전처리부분으로써 한번 사용하면 프로그램 전역으로 각인되는... 마치 전역변수와같은 약간은 비효율적인 역기능을 가져온다. 이 문제를 해결하기위해서 약간의 스코프롤을 적용한 const 제한자가 더욱 효율적인 자료형이 되겠다. 원한다면 전역변수의 역활도 할수 있을뿐더러 블럭내에서만 활용할수도있기때문이다. 단. const제한자는 변수를 선언과 동시에 초기화 해줘야만 한다.

const int a;
a=100;

위 소스는 100% 에러가뜬다. 제한자는 그 의미를 변화시킬수없다.
===============================================================================
const int * n;
데이터 상수화.
n이라는 포인터를 통해 데이터가 조작됨을 막겟다.
메모리공간자체가 상수화 된것은 아니므로 변수를 통해 데이터를 변경하는것은 가능.

int * const n;
포인터 상수화.
n이라는 포인터가 어떤 변수를 가르키는데 그 변수말고 다른 변수를 가르키도록
포인터가 지닌 값을 바꾸려고하는것을 막는다.

const int * const n;
데이터 상수화+포인터 상수화
위 두가지를 합한것.

Tag // c, c++, const, 제한자

댓글을 달아 주세요

  1. sky is blue 2008/03/14 21:34  address  modify / delete  reply

    제목오타발견