'static'에 해당되는 글 1건

6장정리

C++프로그래밍/C++ 2007. 7. 19. 09:35

1. 클래스와 const
int a=10;
int b=20;
const int a=20;  //n값의 변경 불가능
const int* p=&a;  // 포인터p가 가리키는 변수 a를 상수화 시킨다.
                        // 포인터p가 a를 바라봤을때 상수처럼 보인다..
                        // *p=30 (x) a=20(o)
int* const p=&a; // p라는 값 자체를 상수화 시킴
                       // 프로그램이 종료될때까지 p는 a라는 변수를 가리키고 있어야함.
                       // p=&b (x) *p=30(o)

const int* const p=&a;  //위의 두가지 기능을 다 가짐


멤버변수의 상수화와 초기화

#include <iostream>

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

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);
 }
 void ShowData()
 {
  cout<<"이름 : "<<name<<endl;
  cout<<"학과 : "<<major<<endl;
  cout<<"학번 : "<<id<<endl;
  cout<<"나이 : "<<age<<endl;
 }
};

int main()
{
 Student jslee(20011520,23,"이재성","컴공");
 Student jejung(20050000,21,"흰둥이","간호");

 jslee.ShowData();
 cout<<endl;
 jejung.ShowData();
 return 0;
}

클래스 내의 멤버변수 int를 상수화 시키고 싶다..왜?  id는 하나밖에없잖아.변경할일없음.
그래서..저렇게 const로 상수화를 시켰어..그럼 id란 멤버는 쓰레기값을 가지게 될거라고,왜?초기화를 안했으니까 근데 const키워드를 붙였으니까 id란 멤버는 그 쓰레기값으로 정해졌어 이제 바꿀수 없어....일단 여기서 문제점이 생긴다..상수화를 시켰는데 메인함수에서 객체를 생성하면서 생성자에서 상수화된 id값의 변경을 시도 하고 있어..이거 안되지?에러나지..
일단 상수화가 됐는데 어떻게 바꾸냔 말야..자 그래서..제공하는 문법..짜잔.~~바로
멤버이니셜라이져   생성자의 매개변수선언부분 뒤에 :id(_id)를 추가시켜야돼.
그러면 초기화가되.ㅋㅋㅋ 멤버이니셜라이져는 생성자의 몸체보다 먼저실행이된다..
Student(int _id, int _age, char* _name, char* _major) :id(_id)
 {
  //id=_id;  
  age=_age;
  strcpy(name,_name);
  strcpy(major,_major);
 }


이렇게 말이지.. 사용법은 간단하지..참.구조체나 클래스의 멤버변수는 선언과 동시에
초기화가 불가능하단걸 잊지말라규~~!!

const 멤버함수

#include <iostream>

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

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);
 }
 void ShowData() const
 {
  cout<<"이름 : "<<name<<endl;
  cout<<"학과 : "<<major<<endl;
  cout<<"학번 : "<<id<<endl;
  cout<<"나이 : "<<age<<endl;
 }
};

int main()
{
 Student jslee(20011520,23,"이재성","컴공");
 Student jejung(20050000,21,"흰둥이","간호");

 jslee.ShowData();
 cout<<endl;
 jejung.ShowData();
 return 0;
}

여기서는 ShowData라는 멤버 함수를 상수화 시키고 있어..
일단. 멤버함수가 상수화되면 이함수를 통해서 멤버변수의 값이 변경되는것은 허용되지않음.
무슨말인고 하니 자..예문을 하나 써봅시다.

 void ShowData() const
 {
  ( age=30; )
  cout<<"이름 : "<<name<<endl;
  cout<<"학과 : "<<major<<endl;
  cout<<"학번 : "<<id<<endl;
  cout<<"나이 : "<<age<<endl;
 }

이렇게 있단말야? 그럼 저함수는 일단 멤버함수니까 private의 멤버변수에 접근이 가능해
근데 잘봐 const로 선언되어있지.상수가 됐단말야 함수자체가..근데 함수 몸체부분에서
age를 30으로 바꿀려고해..안된다고..변경 불가..ㅇㅋ?

자 그럼...좀 업그레이드된 const멤버함수를 보자

class Count{
 int cnt;
public:
 Count() :cnt(0){}
 int* GetPrt() const{
  return &cnt;
 }
 void Increment(){
  cnt++;
 }
 void ShowData() const{
  ShowIntro();
  cout<<cnt<<endl;
 }
 void ShowIntro() {
  cout<<"현재 count의 값 :"<<endl;
 }
};
자 함수 2개에 const키워드가 붙어있어..이거 별 문제 없어 보이지?
일단 상수함수의 특징을 하나 써보고 설명하자.
상수화된 함수는 상수화 되지 않은 함수의 호출을 허용하지 않을뿐만 아니라 멤버변수의
포인터를 리턴하는것도 허용하지 않는다.

우선 GetPrt함수를 보면 함수내부에서 멤버변수를 조작하는 문장은 보이질 않아.
그런데 리턴하는 값이 먼지 잘봐..멤버변수의 주소 를 리턴하고 있어. 어.저기 함수이 특징을 보면 알겠지만 주소를 리턴한다는건 뭐야? 그 멤버변수를 조작할 가능성이 있다는거지..
그래서 저 함수는 잘못이 된거고.. 두번째 ShowData함수를 보면 상수화가 되었으니 함수내에서 멤버변수의 변경이 불가하지..근데 함수를 보면 다시 ShowIntro라는 함수를 호출해.
어머?! ShowIntro함수를 보면..언제든 함수 몸체부분에 멤버변수를 조작할수있는 문장을
집어넣을수가 있지..우리의 const 님께선 이것조차 허용을 안한단 거야..일단 ShowData가
상수화가 되었으면 상수화 되지않은 ShowIntro라는 함수를 호출못해..아니 안해..
자 그럼..저 클래스의 문제점을 고쳐보실까나
class Count{
 int cnt;
public:
 Count() :cnt(0){}
const int* GetPrt() const{
  return &cnt;
 }
 void Increment(){
  cnt++;
 }
 void ShowData() const{
  ShowIntro();
  cout<<cnt<<endl;
 }
 void ShowIntro() const{
  cout<<"현재 count의 값 :"<<endl;
 }
};

저렇게 파란색으로 되어있는 부분에 const를 넣어주면되..
그럼GetPrt함수는 리턴되는 주소값이 상수화가 되니까..멤버변수 조작이 불가능하구
ShowIntro함수도 상수화가 되었으니 ShowData에서 맘놓고 호출할수 있다규~~!!
아고 허리야..

const 객체

#include <iostream>

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

class AAA{
 int num;
public:
 AAA(int _num) : num(_num){}
 void Add(int n){
  num+=n;
 }
 void ShowData(){
  cout<<num<<endl;
 }
};

int main()
{
 const AAA aaa(10);
 aaa.Add(10);
 aaa.ShowData();
 return 0;
}

 객체 aaa를 생성하면서 상수화를 시키고 있어..자..이렇게 객체가 상수화가 되면 말야
어떠한 경로를 통해서든 멤버변수의 조작은 불가능 해질뿐만 아니라 상수화된 멤버함수만 호출이 가능해진다..일반 멤버함수는 멤버변수를 조작하지 않더라도 호출이 불가능해.

const와 함수오버로딩
void function(int n) const{...}
void function(int n) {...}
저 두개의 함수는 이름도 같고 매개변수로 전달받는 수도 같고 리턴타입도 같다
하지만 하나는 const로 상수화가 되었으므로 함수오버로딩이 가능하데..이런 미친.
그리고, 상수화된 함수보다 상수화 되지 않은 함수가 우선순위가 높댄다..

class AAA{
 int num;
public:
 AAA(int _num) : num(_num){}
 void ShowData(){
  cout<<"void ShowData()호출"<<endl;
  cout<<num<<endl;
 }
 void ShowData() const {
  cout<<"void ShowData() const호출"<<endl;
  cout<<num<<endl;
 }
};

int main()
{
 const AAA aaa(10);
 AAA bbb(20);
 aaa.ShowData();
 bbb.ShowData();
 return 0;
}


자 클래스 내에 함수 두개는 오버로딩되..위에서 설명했지..그럼 메인함수를 쳐보자고..ㅋㅋ
일단 객체 aaa를 생성하면서 상수화 시켜줬으니까 멤버변수조작 불가하고 상수화된 멤버함수만 호출한다..그럼 객체aaa에선 void ShowData() const호출  이값이 출력되겠지
근데 객체bbb를보자고..다른건 다 제껴두고 저건 함수 두개 전부 호출이 가능해..그럼..어떻게 한다? 그렇지..상수화 되지 않은 함수가 우선순위가 높으므로..상수화 되지 않은 함수가
호출이 되면서 void ShowData()호출  이게 출력이 된다규~~

2. 클래스와 static
아 힘들다..
힘드니까 일단 예제보자..ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ

#include <iostream>

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

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;
 }
 void ShowData()
 {
  cout<<"이름 : "<<name<<endl;
  cout<<"나이 : "<<age<<endl;
 }
};

int main()
{
 Person p1("jslee",25);
 Person p2("girl",19);

 return 0;
}

이 예제의 의도는 객체가 생성될때마다 n번째 객체가 생성되었다는 메세지를 출력하고 싶은거야..헐..별.. 이뭐병. ㅋ
그래서 객체가 생성될때마다 참조해야되는(클래스내에서 생성자에서 참조하기위해)변수를 전역적으로 선언했지..어디서든 접근이 가능하게 근데 객체지향에선 전역이라는 개념이없데
그럼 어떻게해? 저기 전역으로 선언되있는 변수를 클래스 안에꾸겨 넣어야지뭐..함 넣어보자.

class Person{
 char name[20];
 int age;
 int count;
public:
 Person(char* _name,int _age){
  count=1;
  strcpy(name,_name);
  age=_age;
  cout<<count++<<"번째 person 객체생성"<<endl;
 }
 void ShowData()
 {
  cout<<"이름 : "<<name<<endl;
  cout<<"나이 : "<<age<<endl;
 }
};

자 넣었다.. private공간에 넣어주고 생성자내에서 1로 초기화 시켜줬어..
자 그럼? 객체를 생성할때~~마다..저기 저 count값은 1이야
그럼 뭐? 생성할때마다 1번째.1번째 1번째 ...객체를 생성했다고 지랄할거란 말이지..

사용자 삽입 이미지

요렇게..그럼 안되 우리가 원하는 건 뭐?
사용자 삽입 이미지
이걸 원하는거야 그지 ㅋㅋㅋ
어떻게 해야 저딴식으로 나올려나..하고 봤더니..static멤버 초기화 라는 문법이 존재해..헐
나쁜놈들.어떻게 해야 하느냐..

class Person{
 char name[20];
 int age;
 static int count;
public:
 Person(char* _name,int _age){
  strcpy(name,_name);
  age=_age;
  cout<<count++<<"번째 person 객체생성"<<endl;
 }
 void ShowData()
 {
  cout<<"이름 : "<<name<<endl;
  cout<<"나이 : "<<age<<endl;
 }
};

int Person::count=1;
//Person::count=1;
int main()
{
 Person p1("jslee",25);
 Person p2("girl",19);

 return 0;
}

일단 멤버변수를 static로 선언해주고..저렇게 static멤버를 초기화 해 주어야해
static 멤버의 특징..(멤버라고 하기엔 좀 거시기 하다)
1)메인 함수가 호출되기도 전에 메모리 공간에 올라가서 초기화가 된다. 따라서public로 선언이 된다면 객체생성이전에도 접근이 가능하다.
2)객체의 멤버로 존재하는것이 아니고 다만 선언되어있는 클래스내에서 직접 접근할수 있는 권한이 부여된 것이다.

아..어렵다..

#include<iostream>

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

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;
 }
};

int AAA::n=1;

int main()
{
 AAA a1(10);
 a1.ShowData();
 AAA a2(20);
 a2.ShowData();

 return 0;
}

이걸 설명하자면..일단 static는 메인함수가 호출되기도 전에 메모리에 올라가서 초기화가
된다고 하였다!! 그지 1로 초기화가 되었을꺼야..저기 static멤버초기화 문장이 있잔아..
그럼..객체 a1을 생성하면서 1이 증가해..생성자내에서..2가됐지..객체a2를생성하면서3이되
그럼 ShowData란 함수로 각각 객체를 출력해 줄때..n의 값은 2,3이 출력이 된단 소리지..
여기서 두번째 특징인데..만약에 static멤버(?)가 객체의 멤버로 존재를 한다면..
두번의 객체생성과 출력과정에서 둘다 2가 출력이 되어야해..멤버로 존재를 한다면
근데 2,3이 출력이 됐단 소리는 static멤버(?)가 객체의 멤버라는 소리가 아니지..휴..
접근을 할수있는 권한만 있을뿐이지 절대 멤버변수가 아니다..참고로 이강의 보면서
내가이해했던건..static변수는 메모리상에딱 한번만 초기화되고 그담부터초기화안된다
이렇게 알고있던거적용하니까 별무리없이 이해되던데...;;

그래서.우리는 static멤버변수나 멤버함수는 객체의 멤버가 아니기때문에 클래스변수
클래스 함수
라고 한다.

3. 그외의 키워드
explicit & mutale
이건 걍 예제보고 이해하자..


끝~~!!!
블로그 이미지

百見 이 不如一打 요 , 百打 가 不如一作 이다.

,