jam 블로그

[C++] 006. static 멤버와 const 멤버 본문

개발 및 관련 자료/C

[C++] 006. static 멤버와 const 멤버

kid1412 2013. 5. 12. 20:07
728x90

I. 클래스와 const

  • const 키워드에 대한 복습

    • 첫째. const 키워드는 변수의 선언 앞에 붙어서 변수를 상수화한다.
    • 둘째. const 키워드는 포인터가 가리키는 데이터를 상수화 한다.
    • 셋째. const 키워드는 포인터 선언 시 이름 앞에 붙어서 포인터 자체를 상수화한다.
  • 멤버 변수의 상수화, 그리고 초기화
  1. #include <iostream>
  2. using namespace std;
  3. class Student
    {
     const int id;
     int age;
     char name[20];
     char major[30];
    public:
     Student(int _id, int _age, char* _name, char* _major)
     {
      id = _id;
      age = _age;
      strcpy(name,_name);
      strcpy(major,_major);
     }
  4.  void ShowData()
     {
      cout<<"이름 : "<<name <<endl;
      cout<<"나이 : "<<age<<endl;
      cout<<"학번 : "<<id<<endl;
      cout<<"학과 : "<<major<<endl;
     }
    };
  5. int main()
    {
     Student Kim(1234,23,"l","3");
     Student Ho(12315,34,"g","re");
  6.  Kim.ShowData();
     cout<<endl;
     Ho.ShowData();
     return 0;
    }
  •  위의 소스는 컴파일이 안된다. 이유는 id를 초기화 하려고 하는데  id는 const로 설정 되어 있어서 초기화가 되지 않는다.

    • 이럴때에는 멤버 이니셜라이저 라는 문법을 사용하면 된다.
  1.   public:
     Student(int _id, int _age, char* _name, char* _major) : id(_id)
     {
      age = _age;
      strcpy(name,_name);
      strcpy(major,_major);
     }
  • 위처럼 클래스를 바꿔주면 잘된다. : id(_id)는 멤버 변수 id를 매개 변수 _id로 초기화한다는 뜻이다.

 

  • const 멤버 함수

    • 멤버 함수가 상수화되면, 이 함수를 통해서 멤버 변수의값이 변경 되는 것은 허용되지 않는다.
  1.  #include <iostream>
  2. using namespace std;
  3. class Student
    {
     const int id;
     int age;
     char name[20];
     char major[30];
    public:
     Student(int _id, int _age, char* _name, char* _major) : id(_id),age(_age)
     {
      strcpy(name,_name);
      strcpy(major,_major);
     }
  4.  void ShowData() const
     {
      cout<<"이름 : "<<name <<endl;
      cout<<"나이 : "<<age<<endl;
      cout<<"학번 : "<<id<<endl;
      cout<<"학과 : "<<major<<endl;
     }
    };
  5. int main()
    {
     Student Kim(1234,23,"l","3");
     Student Ho(12315,34,"g","re");
  6.  Kim.ShowData();
     cout<<endl;
     Ho.ShowData();
     return 0;
    }
  • ShowData 멤버함수를 const 하였다.
  1. #include <iostream>
  2. using namespace std;
  3. class Count
    {
     int cnt;
    public:
     Count() : cnt(0){}
     int* GetPtr() const{
      return &cnt;
     }
     void Increment()
     {
      cnt++;
     }
     void ShowData()const
     {
      ShowIntro();
      cout<<cnt<<endl;
     }
     void ShowIntro()
     {
      cout<<"현재 count의 값 : "<<endl;
     }
    };
  4.  int main()
    {
     Count count;
     count.Increment();
     count.ShowData();
     return 0;
    }
  • 위의 클래스부분쪽에 const를 쓴 부분을 보자 int *GetPtr() const 와 ShowData() const에서 오류가 나는데 이유는 const된 함수는 const화 되지 않은 함수의 호출을 허용하지 않을 뿐더러 멤버 변수의 포인터를 리턴하는 것도 허용하지 않는다.
  • 출력하려면 어떻게 해야할까? 리턴 받는 값이나 리턴 하는 곳에 const화를 시켜주면 된다.
  1. class Count
    {
     int cnt;
    public:
     Count() : cnt(0){}
    const int* GetPtr() const{
      return &cnt;
     }
     void Increment()
     {
      cnt++;
     }
     void ShowData() const
     {
      ShowIntro();
      cout<<cnt<<endl;
     }
     void ShowIntro() const
     {
      cout<<"현재 count의 값 : "<<endl;
     }
    };
  • 위의 소스 처럼 바꾸면 컴파일이 되긴한다. 저렇게 되는 소스 보다 차라리 const 안쓰는 쪽으로 하는 것이 좋을 것이다.

 

  • const와 함수 오버로딩

    • 상수 함수냐 아니냐에 따라서도 함수 오버로딩은 성립한다.
  1.  #include <iostream>
  2. using namespace std;
  3. class AAA
    {
     int num;
    public:
     AAA(int _num):num(_num){}
     void ShowData()
     {
      cout<<"void ShowData(0 호출"<<endl;
      cout<<num <<endl;
     }
     void ShowData() const
     {
      cout<<"void ShowData() const 호출"<<endl;
      cout<<num<<endl;
     }
    };
  4. int main()
    {
     const AAA aaa1(20);
     AAA aaa2(70);
     aaa1.ShowData();
     aaa2.ShowData();
     return 0;
    }
  •   const가 있고 없고의 차이로 함수가 달라지는 것을 알 수 있다.

II. 클래스와 static

  • 전역 변수가 필요한 상황
  1. #include <iostream>
  2. using namespace std;
  3. int count = 1;
    class Person
    {
     char name[20];
     int age;
    public:
     Person(char* _name,int _age)
     {
      strcpy(name,_name);
      age = _age;
      cout<<count++<<"번째 Person 객체 생성 "<<endl;
  4.  }
     void ShowData()
     {
      cout<<"이름 : "<<name;
      cout<<"나이 : "<<age;
     }
    };
  5. int main(void)
    {
     Person p1("Lee",13);
     Person p2("Jong",22);
     return 0;
    }
  •  위에서 int count =1; 처럼 전역변수로 선언 하면 값이 증가를 한다.

    • 완벽한 객체지향적 프로그래밍하기 위해서바꿔 보자.

 

  •  static 멤버의 특징

    • 첫째 main 함수가 호출되기도 전에 메모리 공간에 올라가서 초기화된다. 따라서 public으로 선언이 된다면, 객체 생성 이전에도 접근이 가능하다.
    • 둘째 객체의 멤버로 존재하는 것이 아니다. 다만 선언되어 있는 클래스 내에서 직접 접근할 수 있는 권한이 부여된 것이다.
  1.  #include <iostream>
    using namespace std;
  2. class AAA
    {
    public:
     static int n;
    };
  3. int AAA::n =1;
  4. int main()
    {
     cout<<AAA::n<<endl;
     AAA::n++;
     cout<<AAA::n<<endl;
     return 0;
    }
  • static 멤버는 main 함수가 호출되기 이전에 이미 메모리 공간에 올라가서 초기화된다.

    • 초기화를 해주려면 생성자를 써주면 좋겠지만 객체 생성되기 전에 메모리에 올라가기 때문에 int AAA::n = 1; 이런식으로 초기화를 해줘야 한다.
  1. #include <iostream>
    using namespace std;
  2. class AAA
    {
     int val;
     static int n;
    public:
     AAA(int a =0)
     {
      val = a;
      n++;
     }
     void ShowData()
     {
      cout<<"val : "<<val<<endl;
      cout<<"n : "<<n<<endl;
     }
    };
  3. int AAA::n =1;
  4. int main()
    {
     AAA a1(10);
     a1.ShowData();
  5.  AAA a2(20);
     a2.ShowData();
     return 0;
    }
  •  위의 소스 결과를 보면  static int n이 private로 선언되어 있기 때문에 외부(main)에서는 허용이 안된다.

    •  변수 n은 객체 안에 존재 하지 않는다. 다만 바로 접근할 수 있는 권한이주어져있어서 ShowData에서 접근을 할 수 있는 것이다.
    • static 멤버 변수나 멤버함수는 객체의 멤버가 아닌 클래스 변수, 클래스함수라고 표현하는것이 더 정확하다.

 

  • 그 이외의 키워드 : explicit & mutable

    • 명시적인 것만 허용한다! : explicit
  1.  #include <iostream>
    using namespace std;
  2. class AAA
    {
    public:
     explicit AAA(int n)
     {
      cout<<"explicit AAA(int n)"<<endl;
     }
    };
  3. int main()
    {
     AAA a1(10);
     AAA a2 = 10;
     return 0;
    }
  •  위의 소스에서 생성자 AAA 앞에 explicit 키워드를 써서 묵시적인 호출을 허용하지 않게 했다.

    • main 함수 안에 AAA a1(10)은 되지만 AAA a2 = 10 은 묵시적으로 AAA a2(10)으로 변환이 되는데 그것을 허용하지 않아서 오류가 난다.

 

  • 예외를 둔다! : mutable
  1. #include <iostream>
    using namespace std;
  2. class AAA
    {
    private:
     mutable int val1;
     int val2;
    public:
     void SetData(int a, int b) const
     {
      val1 = a;
      val2 = b;
      cout<<val1<<" "<<val2<<endl;
     }
    };
  3. int main()
    {
     AAA a1;
     a1.SetData(10,20);
     return 0;
    }
  •  public 에 있는 SetData를 const로 지정하여 값을 못 바꾸게 만들고 메인에서 값을 집어 넣으면 원래 val1,val2가 오류가 나야하나 val1에서는 오류가 나지 않는다.

    • val1에 mutable를 붙여서 예외로 오류가 안나게 된 것이다. (되도록 안쓰는 편이 좋다.) 

'개발 및 관련 자료 > C' 카테고리의 다른 글

[C++] 008. 상속과 다형성  (0) 2013.05.12
[C++] 007. 상속(Inheritance)의 이해  (0) 2013.05.12
[C++] 005. 복사 생성자  (0) 2013.05.12
[C++] 004. 클래스의 완성  (0) 2013.05.12
[C++] 003. 클래스의 기본  (0) 2013.05.12
Comments