'const'에 해당되는 글 2건

Programming/C C++
C와 C++의 차이중 가장 큰 것이 바로 Class개념입니다. 현재에도 Class는 java나 C#그리고 VB.NET에까지 다양한 언어에서 객체지향프로그래밍(OOP)으로 Class개념이 사용되고 있습니다.

C++에서 Class는 원래 C의 구조체를 좀더 효휼적으로 바꾸고자 해서 등장했다는 얘기가 있습니다. 실제로 정말 그런지는 확실하지 않지만 만일 C에서 구조체를 접해보신 경우라면 'C의 구조체에 변수 Member와 더불어 함수까지도 포함시킬 수 있게 한것이 Class다.' 라고 이해(꼭 그렇다는 것은 아니지만...)하시면 될듯 합니다.

다음은 C++에서 구조체를 활용한 예입니다.

#include <iostream.h>
#include <string.h>

main()
{
  struct exam{
    char name[15];
    int kuk;
    int mat;
    int eng;
  };
 
  exam student;
 
  strcpy(student.name, "kim young soo");
  student.kuk = 90;
  student.mat = 100;
  student.eng = 80;
 
  cout << "학생이름 : " << student.name << endl;
  cout << "국어점수 : " << student.kuk << endl;
  cout << "수학점수 : " << student.mat << endl;
  cout << "영어점수 : " << student.eng << endl;
 
  return 0;
}


exam구조체를 선언하고 각 변수 Member에 값을 설정한뒤 설정한 값을 확인하는 Program입니다.


Pogram에서 쓰인 구조체를 Class화 하려면 다음과 같이 바뀔 수 있습니다.

class exam{
  private:
    char name[15];
    int kuk;
    int mat;
    int eng;
 
  public:
    void name_input(char *nm);
    void memberprint();
   
    int kuk_input(int pt);
    int mat_input(int pt);
    int eng_input(int pt);
};

위 구조체를 class로 바꾼것으로서 exam을 Class로 정의하였습니다. 이 Class안에 name과 kuk, mat, eng라는 Member변수와 더불어 name_input, memberprint, kuk_input, mat_input, eng_input이라는 Member함수도 같이 존재하도록 하였습니다.

여기서 Member함수는 위 Member변수를 설정할 수 있도록 하기 위해 정의한 것입니다. (Memberprint()함수는 각 설정값을 확인하기 위한 용도로 사용하려고 합니다.)

위 Class에서 private와 public은 현재 Class에서 어떤 Member에 대해 접근 가능하게 할지 또 어떤 Member에 대해서 접근을 막을지에 대해 지정하는 것이라고 보시면 됩니다. 이때 private은 해당 Member에 대해 접근을 불가능하게 하는 Keyword이며 public는 접근을 허락하는 Keyword입니다.(protected 라는 Keyword가 있지만 이는 잠시 후 설명드리도록 하겠습니다.)

물론 Member변수에 public Keyword를 쓴다면 접근이 가능하게 할 수도 있습니다.

class exam{
  private:
    char name[15];
    int kuk;
    int mat;
    
  public:
    void name_input(char *nm);
    void memberprint();
   
    int kuk_input(int pt);
    int mat_input(int pt);
    int eng_input(int pt);

    int eng;
};


eng Member변수를 public하위에 정의하였습니다.

student.eng = 90;

public으로 정의된 eng는 직접접근이 가능합니다.

private의 경우에는 생략할 수도 있습니다. 이는 처음 Member는 private로 처리하는 것이 기본으로 되어 있기 때문에 가능한 것입니다.

class exam{
    char name[15];
    int kuk;
    int mat;
    int eng;
 
  public:
    void name_input(char *nm);
    void memberprint();
   
    int kuk_input(int pt);
    int mat_input(int pt);
    int eng_input(int pt);
};

이렇게 생략하면 다른 Keyword가 등장할때까지 모든 Member는 private로 처리됩니다.

이와 더불어 각 Keyword를 반복해서 쓸 수도 있습니다. 이는 해당 Member를 특성에 따라 Group으로 구분하고자 할때 유용하게 사용됩니다.

class exam{
  private:
    char name[15];
 
  public:
    void name_input(char *nm);
    void memberprint();
 
  public:
    int kuk_input(int pt);
    int mat_input(int pt);
    int eng_input(int pt);
   
  private:
    int kuk;
    int mat;
    int eng;
};

private과 public Keyword는 여러번 쓸 수 있습니다.

Class안의 Member변수를 private에 둘것인가 public에 둘것인가 또는 Member함수를 private에 둘것인가 public에 둘것인가 하는 문제는 어디까지나 개발자의 자유이므로 어떤형태로든지 작성될 수 있습니다.

다음은 위 Class를 실제 Program적용시킨 예입니다.

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
    int kuk;
    int mat;
    int eng;
 
  public:
    void name_input(char *nm);
    void memberprint();
   
    int kuk_input(int pt);
    int mat_input(int pt);
    int eng_input(int pt);
};

void exam::name_input(char *nm)
{
  strcpy(name, nm);
}

int exam::kuk_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  kuk = pt;
 
  return ptp;
}

int exam::mat_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  mat = pt;
 
  return ptp;
}

int exam::eng_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  eng = pt;
 
  return ptp;
}

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl << endl;
  cout << "국어점수 : " << kuk << endl;
  cout << "수학점수 : " << mat << endl;
  cout << "영어점수 : " << eng << endl;
}

main()
{
  exam student;
 
  int kukp;
  int matp;
  int engp;
 
  student.name_input("youngsoo");
 
  kukp = student.kuk_input(80);
  matp = student.mat_input(91);
  engp = student.eng_input(94);
 
  student.memberprint();

  cout << "국어점수(가산) : " << kukp << endl;
  cout << "수학점수(가산) : " << matp << endl;
  cout << "영어점수(가산) : " << engp << endl;
 
  return 0;
}


먼저 Program상단에 exam이라는 Class를 정의하였습니다. 이렇게 선언된 Class를 실제 사용하기 위해서는 Class의 Object를 생성해야 하며 생성 방법은 구조체를 사용할때와 비슷합니다.

exam student;

exam Class에서 student의 Object를 생성합니다.

보시는 바와 같이 Class는 Object생성해야 사용할 수 있습니다. Class에 바로 접근할 수 없다는 얘기인데 그 이유는 어느 한쪽에서 Class Member의 값을 수정하면 다른쪽에도 영향을 받을 수 있기 때문으로 Class를 사용할때는 Class자체를 특정이름으로 복사해서 사용해야할 필요성이 있는 것입니다. 이 Class의 복사본을 생성하는 과정을 흔히 Instance라고 하며 Instance에 의해 생성된 것(여기서는 student)을 Object(객체)라고 합니다.

위 Class는 Member변수와 Member함수를 가지도록 하였고 모든 Member변수는 private을 모든 Member함수는 public Keyword를 사용하였습니다. 따라서 Class의 Member변수에는 직접적으로 접근할 수 없지만 Member함수는 직접 접근이 가능합니다.

앞서 말씀드렸듯이 Class의 Member에는 접근이 불가능하므로 구조체를 사용할때 처럼 직접 값을 설정하는 것은 불가능합니다.

student.kuk = 90;

kuk Member변수는 private에 속하므로 위와 같이 값을 설정할 수 없습니다.

Class를 제대로 사용하기 위해서는 어떻게든 값을 설정해야할 필요가 있습니다. 그래서 public하위에 값을 설정할 수 있는 함수를 정의한 것입니다.

name_input, memberprint, kuk_input, mat_input, eng_input 함수는 public로 선언되었으므로 private로 선언된 Member변수와는 달리 직접 접근이 가능합니다. 이렇게 선언된 Member함수는 실제 이 함수가 어떤 기능을 수행할지 그 본체를 구현해야 하며 이때 구현은 Class밖에서 다음과 같은 방식으로 정의됩니다.

void exam::name_input(char *nm)
{
  strcpy(name, nm);
}

int exam::kuk_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  kuk = pt;
 
  return ptp;
}


Class안에 선언된 함수는 위와 같이 그 본체를 구현합니다.

위와 같은 방식은 Class의 특정 Member변수를 설정할때 꽤 유용하게 사용될 수 있는 부분입니다. 예를 들어 국어시험에서 모든 문제를 틀리면 0점이 됩니다. 시험을 아무리 못봐도 0이하(-값)은 될 수 없는데 만일 kuk이라는 Member변수에 -100을 설정하게 된다면 이것 자체가 오류가 됩니다.

이러한 상황이 생기는 것을 막으려면 kuk_input()함수를 다음과 같이 수정해야 합니다.

int exam::kuk_input(int pt)
{
  if (pt < 0){
    cout << "점수설정에 오류가 있습니다." << endl;
    return 0;
  }
 
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  kuk = pt;
 
  return ptp;
}

pt값이 0이하이면 kuk member변수에 값을 설정할 수 없도록 합니다. 즉, 특정값에 따라 원하는 처리를 수행할 수 있도록 할 수 있는 것입니다.

또한 Class구현시 Class에서 선언된 각 Member함수와 실제 함수의 본체를 별도로 하는것이 불편하다면 다음과 같이 아예 Class안에서 모든것을 해결할 수도 있습니다.

class exam{
  private:
    char name[15];
    int kuk;
    int mat;
    int eng;
 
  public:
    void name_input(char *nm){
      strcpy(name, nm);
    }
   
    void memberprint(){
      cout << "학생이름 : " << name << endl << endl;
      cout << "국어점수 : " << kuk << endl;
      cout << "수학점수 : " << mat << endl;
      cout << "영어점수 : " << eng << endl;
    }
   
    int kuk_input(int pt){
      int ptp = pt;
 
      if (pt >= 90)
        ptp = pt + 3;
 
      kuk = pt;
 
      return ptp;
    }
   
    int mat_input(int pt){
      int ptp = pt;
 
      if (pt >= 90)
        ptp = pt + 3;
 
      mat = pt;
 
      return ptp;
    }
   
    int eng_input(int pt){
      int ptp = pt;
 
      if (pt >= 90)
        ptp = pt + 3;
 
      eng = pt;
 
      return ptp;
    }
};

Class안에서 함수구현까지 모두 처리하고 있습니다.

위 함수에서 쓰인 exam:: 부분은 exam Class의 함수를 구현하겠다는 의미가 됩니다. 이렇게 함수를 구현한뒤 구조체처럼 함수를 호출하면 실제 위와 같이 구현된 동작을 수행하게 되는 것입니다.

참고 :
int exam::kuk_input(int pt)에서 ::문자를 Scope연산자라고 합니다. Scope연산자는 다양한 역활을 수행하는데 여기에서는 Class의 Member에 접근하도록 하는 역활을 수행하고 있습니다. 이때 Scope연산자는 exam의 kuk_input member 처럼 ~의 ~ 로 해석될 수 있습니다.

student.name_input("youngsoo");
 
  kukp = student.kuk_input(80);
  matp = student.mat_input(91);
  engp = student.eng_input(94);
 
student.memberprint();

Class의 함수를 호출합니다.

Class안의 각 함수는 Class안의 Member변수에 값을 설정할 수 있도록 구현되었습니다.(memberprint()함수는 값을 확인하도록 하였습니다.) 즉, Class안의 Member함수를 통해 Member변수에 접근하고 있는 것입니다.(이는 위에서 말씀드린 Scope연산자의 의해 가능해 집니다.)

이렇게 값을 설정하고 memberprint()함수를 호출하면 각 Member변수의 값을 확인할 수 있습니다.

위 Member함수에서 name이 아닌 kuk, mat, eng member변수를 설정하는 함수를 보면

int exam::kuk_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  kuk = pt;
 
  return ptp;
}

int exam::mat_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  mat = pt;
 
  return ptp;
}

int exam::eng_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  eng = pt;
 
  return ptp;
}


pt값이 90이상일때 3을 더하도록 구현되어 있음을 알 수 있습니다. 점수로 치면 90점 이상일때 가산점 3을 더하도록 하기 위한 의도입니다. 각 함수에서는 가산점이 붙은 값을 return하고 있으며 main()은 위 세개의 함수를 호출할때 계산된 가산점을 받도록 하고 있습니다.

kukp = student.kuk_input(80);
matp = student.mat_input(91);
engp = student.eng_input(94);

이처럼 Class의 Member함수도 일반 함수처럼 void로 할 수 있고 필요하다면 특정 값을 받도록 할 수도 있습니다. Class안의 함수라고 해서 일반함수와 특별히 다를 것은 없습니다.


만일 같은 Class에서 파생된 Object가 2개상이 있다면 상호간의 Object대입을 통해서 값을 초기화 할 수도 있습니다.

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
    int kuk;
    int mat;
    int eng;
 
  public:
    void name_input(char *nm);
    void memberprint();
   
    int kuk_input(int pt);
    int mat_input(int pt);
    int eng_input(int pt);
};

void exam::name_input(char *nm)
{
  strcpy(name, nm);
}

int exam::kuk_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  kuk = pt;
 
  return ptp;
}

int exam::mat_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  mat = pt;
 
  return ptp;
}

int exam::eng_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  eng = pt;
 
  return ptp;
}

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl << endl;
  cout << "국어점수 : " << kuk << endl;
  cout << "수학점수 : " << mat << endl;
  cout << "영어점수 : " << eng << endl;
}

main()
{
  exam student, student2;
 
  int kukp;
  int matp;
  int engp;
 
  student.name_input("youngsoo");
 
  kukp = student.kuk_input(80);
  matp = student.mat_input(91);
  engp = student.eng_input(94);
 
  student.memberprint();
  student2 = student;
  student2.memberprint();
 
  return 0;
}


exam Class로부터 student와 student2라는 Object를 생성하고 student object에서 값을 설정한 후 student2 Object에 student Object를 대입하였습니다.

student.memberprint();

이 후 student2 Object의 값을 확인해 보면 student Object와 값이 일치함을 알 수 있습니다.


위에서는 단일 Object를 설정하여 해당 Class에 값을 설정하였지만 Class를 통해 생성한 Object를 배열로 하면 해당 Class의 복사본을 배열길이만큼 확보할 수 있게 됩니다.

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
    int kuk;
    int mat;
    int eng;
 
  public:
    void name_input(char *nm);
    void memberprint();
   
    int kuk_input(int pt);
    int mat_input(int pt);
    int eng_input(int pt);
};

void exam::name_input(char *nm)
{
  strcpy(name, nm);
}

int exam::kuk_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  kuk = pt;
 
  return ptp;
}

int exam::mat_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  mat = pt;
 
  return ptp;
}

int exam::eng_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  eng = pt;
 
  return ptp;
}

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
  cout << "수학점수 : " << mat << endl;
  cout << "영어점수 : " << eng << endl << endl;
}

main()
{
  exam student[2];
 
  student[0].name_input("youngsoo");
  student[0].kuk_input(80);
  student[0].mat_input(91);
  student[0].eng_input(94);
 
  student[1].name_input("sooyoung");
  student[1].kuk_input(70);
  student[1].mat_input(81);
  student[1].eng_input(84);
 
  student[0].memberprint();
  student[1].memberprint();
 
  return 0;
}


exam student를 exam student[2]로 하여 2개의 배열길이만큼 Object를 생성합니다.

배열도 단일 Object와 똑같이 값을 설정하면 됩니다. [0]이나 [1]을 붙여 몇번째 배열에 Member를 호출하는지만 지정해 주면 되는 것입니다.


다만 일일이 첨자를 붙여 초기화 해주는 것이 불편하다면 문자배열을 초기화 하듯 {}를 써서 한꺼번에 초기화 할 수도 있습니다. 이는 생성자를 통해서 가능한데 자세한 내용은 생성자와 소멸자 부분을 참고해 주시기 바랍니다.

[Develop/C, C++] - [C, C++] Class구현시 생성자와 소멸자 활용

Class를 활용한 다음 Program을 봐주십시오.

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
    int kuk;
 
  public:
    void name_input(char *nm, int i);
    void memberprint();
   
    int kuk_input(int pt);
};

void exam::name_input(char *nm, int i)
{
  strcpy(name, nm);
  kuk = i;
}

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
}

main()
{
  exam student;
 
  student.name_input("youngsoo", 90);
   student.memberprint();
 
  return 0;
}



위 Program에서 Class의 name과 kuk member에 접근하기 위해 Class내에서 memberprint()함수를 public으로 선언하였습니다.

따라서 이 함수외에 다른 외부함수에서는 name과 kuk member에 접근할 수 없게 되었습니다. 왜냐하면 name과 kuk member는 class안에서 private으로 선언되었기 때문입니다.

하지만 Program안에서 private Member에 접근할 수 있는 방법이 있는데 그것은 Class안에 friend함수를 선언하는 것입니다.

class exam{
  private:
    char name[15];
    int kuk;
 
  public:
    void name_input(char *nm, int i);
    void memberprint();
   
    int kuk_input(int pt);
   
    friend void kukinout(exam ea);
};

위와 같이 Class안에서 friend함수를 선언하면 해당 함수는 private나 public의 적용을 받지 않습니다. 왜냐하면 friend함수는 Class의 Member가 아니기 때문입니다. 이것은 단지 Program내에서 kukinout함수가 있으면 이 함수안에서 만큼은 Class의 private Member에 접근을 허용한다라는 의미만 가지고 있을 뿐입니다. 즉, 외부함수와 Class간의 통로역활만 하고 있는 것입니다.

또한 friend함수에서 함수의 인수로 exam형의 인수(exam ea)를 지정하고 있습니다. 이는 Program안에서 kukinout함수를 작성할때 Class의 Member에 접근하기 위해 Class로 부터 파생된 Object를 전달해 줄 필요가 있기 때문입니다.

Class안에서 작성된 friend함수의 특성을 활용하기 위해서는 Program안에서 kukinout라는 똑같은 이름의 함수를 작성해야 합니다.

void kukinout(exam ea)
{
  ea.kuk = 20;
  cout << "국어점수 : " << ea.kuk << endl;
}

인수로 부터 전달받은 Object를 통해 Private Member인 kuk member의 값을 설정하고 그 값을 확인하고 있습니다.

kukinout함수는 Class가 아닌 Program안에서 쓰인 독자적 함수입니다. 따라서 함수의 원형도 선언할 수 있습니다.

class exam{
  private:
    char name[15];
    int kuk;
 
  public:
    void name_input(char *nm, int i);
    void memberprint();
   
    int kuk_input(int pt);
   
    friend void kukinout(exam ea);
};

void kukinout(exam ea);


함수의 원형을 Class밑에 선언하는 이유는 이 원형이 Class선언 이전에 위치하게 되면 exam이 정의되지 않았다는 오류를 일으키기 때문입니다.

이제 지금까지 말씀드린 모든 Code를 모두 조합하여 Program을 작성하면 다음과 같이 될 것입니다.

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
    int kuk;
 
  public:
    void name_input(char *nm, int i);
    void memberprint();
   
    int kuk_input(int pt);
   
    friend void kukinout(exam ea);
};

void kukinout(exam ea);
void exam::name_input(char *nm, int i)
{
  strcpy(name, nm);
  kuk = i;
}

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
}

main()
{
  exam student;
 
  student.name_input("youngsoo", 90);
  student.memberprint();
 
  kukinout(student);
 
  return 0;
}

void kukinout(exam ea)
{
  ea.kuk = 20;
  cout << "국어점수 : " << ea.kuk << endl;
}


kukinout(student); 로 kukinout함수를 호출합니다.


friend 함수는 Program안에서 쓰인 특정 함수에 대해서만 Class의 Member접근을 허용하는 것입니다. 하지만 Class자체를 friend화 하면 해당 Class전체에 대해서 Member접근을 허용할 수 있게 됩니다.

class exam{
  private:
    char name[15];
    int kuk;
 
  public:
    void name_input(char *nm, int i);
    void memberprint();
   
    int kuk_input(int pt);
   
    friend class exam2;
};

class exam2 : public exam{
  private:
    char name[15];
 
  public:
    void name_input(char *nm);
    void memberprint();
};


위와 같이 Class자체를 friend로 선언하면 friend Class는 본래 Class의 모든 Member에 접근할 수 있게 됩니다. 단, Class exam2 : public exam 처럼 본래 Class로 부터 상속받는 Class인 경우에만 가능합니다.

Class의 상속에 대한 내용은 다음 글을 참고하여 주십시오.

[Develop/C, C++] - [C, C++] Class 상속

이렇게 되면 exam2 Class에서는 본래 Class Member를 원하는 대로 다룰 수 있게 됩니다.

void exam2::memberprint()
{
  kuk = 20;
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
}

exam2에서 exam Class의 kuk member에 접근하여 값을 설정하고 그 값을 확인하고 있습니다.(exam2 Class에서 Member변수는 name뿐입니다.)

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
    int kuk;
 
  public:
    void name_input(char *nm, int i);
    void memberprint();
   
    int kuk_input(int pt);
   
    friend class exam2;
};

class exam2 : public exam{
  private:
    char name[15];
 
  public:
    void name_input(char *nm);
    void memberprint();
};

void exam::name_input(char *nm, int i)
{
  strcpy(name, nm);
  kuk = i;
}

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
}

void exam2::name_input(char *nm)
{
  strcpy(name, nm);
}

void exam2::memberprint()
{
  kuk = 20;
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
}

main()
{
  exam student;
  exam2 student2;
 
  student.name_input("youngsoo", 90);
  student.memberprint();
 
  student2.name_input("sooyoung");
  student2.memberprint();
 
  return 0;
}



private는 Member로의 접근방지, public는 Member의 접근허용 용도로 사용됩니다. C++에서는 이와 더불어 protected라는 Keyword가 있습니다. 이것은 일반적으로는 private의 성격을 가지고 있으나 다른 Class가 해당 Class로터 상속될때에는 public성격을 가지는 특징이 있습니다.

Class의 Public는 다음과 같이 Program내에서 접근이 가능하지만

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
    int kuk;
 
  public:
    void name_input(char *nm, int i);
    void memberprint();
};

void exam::name_input(char *nm, int i)
{
  strcpy(name, nm);
  kuk = i;
}

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
}

main()
{
  exam student;
 
  student.name_input("youngsoo", 90);
  student.memberprint();

  return 0;
}



이것을 protected로 고치면 상황은 달라집니다.

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
    int kuk;
 
  protected:
    void name_input(char *nm, int i);
    void memberprint();
};

void exam::name_input(char *nm, int i)
{
  strcpy(name, nm);
  kuk = i;
}

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
}

main()
{
  exam student;
 
  student.name_input("youngsoo", 90);
  student.memberprint();

  return 0;
}



오류발생(접근할 수 없음) Error가 출력되는데 이는 protected Member로의 접근이 오로지 상속된 Class에서만 가능하기 때문입니다.

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
    int kuk;
 
  protected:
    void name_input(char *nm, int i);
    void memberprint();
};

class exam2 : public exam{
  public:
    void input();
    void print();
};

void exam::name_input(char *nm, int i)
{
  strcpy(name, nm);
  kuk = i;
}

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
}

void exam2::input()
{
  name_input("youngsoo", 90);
}

void exam2::print()
{
  memberprint();
}

main()
{
  exam2 student;
 
  student.input();
  student.print();
 
  return 0;
}


exam Class로 부터 상속하여 exam2 Class를 생성합니다.

상속된 Class는 기존 Class에서 protected된 Member에 다음의 형태처럼 접근하는 것이 가능해 집니다.

void exam2::input()
{
  name_input("youngsoo", 90);
}

void exam2::print()
{
  memberprint();
}


상속된 exam2 Class에서 exam Class의 protected Member인 name_input과 memprint Member에 접근하고 있습니다.


위의 friend설명부분에서 쓰인 memberprint()함수를 다시 한번 살펴보겠습니다.

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl << endl;
  cout << "국어점수 : " << kuk << endl;
  cout << "수학점수 : " << mat << endl;
  cout << "영어점수 : " << eng << endl;
}

이 함수에서는 exam Class의 name, kuk, mat, eng member변수의 값을 확인하도록 하고 있습니다. 그런데 만일 이 함수안에 어떠한 이유로 인하여 kuk이라는 변수가 새로 선언되었을때 결과는 어떻게 될까요?

void exam::memberprint()
{
  int kuk = 0;
 
  cout << "학생이름 : " << name << endl << endl;
  cout << "국어점수 : " << kuk << endl;
  cout << "수학점수 : " << mat << endl;
  cout << "영어점수 : " << eng << endl;
}

memberprint()함수안에 kuk이라는 변수를 선언하고 초기값을 0으로 합니다.


Program실행결과가 0으로 나왔습니다. 이는 Class의 kuk Member가 아니라 함수안에서 쓰인 kuk변수값을 가져오고 있기 때문입니다.

이렇게 혼동되는 문제를 해결하는 방법에는 두가지가 있는데 하나는 해당 Member에 Class를 지정해 주는 것이며

cout << "국어점수 : " << exam::kuk << endl;

다른 하나는 This Pointer를 지정하는 것입니다.

cout << "국어점수 : " << this->kuk << endl;

이 This Pointer는 이름에서도 알 수 있듯이 주소값을 갖는 Pointer로서 해당 주소는 다름아닌 Class에서 생성된 Object의 주소를 갖고 있는 것입니다.

결국

exam student;

student.memberprint();


이와같이 하였을때 This에는 student Object의 주소가 담겨져 전달되기 때문에 Class의 kuk Member값을 가져오게 됩니다.

방금전 This Pointer를 사용해 보았는데 이것으로 알 수 있는것은 Class의 Member에 접근하는데 Object를 통해서만 아니라 Pointer를 통해 접근할 수도 있다는 것입니다.

아래 예제는 위에서 다룬 Program에서 점수부분은 빼고 이름만 설정/확인할 수 있도록 간소화한 예제입니다.

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
 
  public:
    void name_input(char *nm);
    void memberprint();
};

void exam::name_input(char *nm)
{
  strcpy(name, nm);
}

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl;
}

main()
{
  exam student;
 
  exam *p = &student;
 
  student.name_input("youngsoo");
  student.memberprint();
 
  p->memberprint();
 
  return 0;
}


student의 Object주소값을 exam형 Class의 Pointer에 전달하고 이 Pointer를 통하여 Class의 memberprint() Member함수에 접근하고 있습니다.

Object의 주소값을 Pointer에 넘기려면 해당 Pointer가 Object가 생성된 Class형으로 선언되어야 하며 이 Pointer에 & 연산자를 통하여 Object의 주소값만 넘겨주기만 하면 됩니다.

이 후 Object의 주소를 전달받은 Pointer는 -> 연산자를 통해 Class의 Member에 접근하도록 합니다.


Class로부터 생성된 Object를 Const로 선언하면 해당 Object에서는 각 Member에 접근할 수 없는 상황이 발생합니다.

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
    int kuk;
 
  public:
    void name_input(char *nm, int i);
    void memberprint();
};

void exam::name_input(char *nm, int i)
{
  strcpy(name, nm);
  kuk = i;
}

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
}

main()
{
  const exam student;

  student.name_input("youngsoo", 90);
  student.memberprint();
 
  return 0;
}


exam Class의 student Object를 const로 선언하였습니다.


잘 아시는 바와 같이 const는 상수입니다. 즉, 값을 바꿀 수 없는 것이기 때문에 Member접근 자체가 차단되는 것입니다.

값을 설정하는 name_input member함수는 그렇다 치고 단순히 값을 조회하는 memberprint()함수까지 차단되는 이유는 뭘까요? 이는 C++ Compiler가 어떤 함수에서 값을 변경하고 또 어떤 함수에서 값을 변경하지 않는지까지는 판단하지 않기 때문입니다.

즉, 값을 변경하는 부분과 값을 변경하지 않는 부분을 구분하지 않기 때문에 아예 모두 틀어막아 버릴 수 밖에 없게 되는 것이죠.

이렇게 되면 값을 확인할 수도 없어서 const로 설정하는 것 자체가 거의 무의하게 되지만 값을 바꾸지 않는 Class의 Member함수에 한하여 const로 선언하게 되면 해당 함수는 사용을 가능하게 할 수도 있습니다.

class exam{
  private:
    char name[15];
    int kuk;
 
  public:
    exam(char *nm, int i);
    void memberprint() const;
};

Class에서 memberprint() Member함수에 const선언하였습니다. memberprint()는 값을 설정하는 부분이 없고 오로지 값을 확인하는 부분만 존재합니다.

또한 해당 Class의 각 Member에 초기값을 설정하기 위해 exam생성자를 선언하였습니다. 만일 생성자가 아닌 기존에서 처럼

void name_input(char *nm, int i);

하여 Member함수로 값을 설정하려고 하면 해당 Object생성시 const로 했을때 값을 설정하는 Member로의 접근이 차단 되므로 초기값을 설정하는 것 자체가 불가능하게 됩니다.

생성자에 대해서는 다음글을 참고하여 주십시오.

[Develop/C, C++] - [C, C++] Class구현시 생성자와 소멸자 활용

Class에서 memberprint()함수에 const를 선언하고 나면 해당 함수의 정의부분에서도 const를 추가해야 합니다.
void exam::memberprint() const
{
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
}

함수 정의 마지막 부분에 const구문을 추가하였습니다.

만일 Class안에서 선언과 정의가 동시에 이루어 지는 경우라면 다음과 작성할 수도 있습니다.

class exam{
  private:
    char name[15];
    int kuk;
 
  public:
    exam(char *nm, int i);
    void memberprint() const {
      cout << "학생이름 : " << name << endl;
      cout << "국어점수 : " << kuk << endl;
    }
};

마지막으로 선언된 생성자에 대한 정의를 작성한 후

exam::exam(char *nm, int i)
{
  strcpy(name, nm);
  kuk = i;
}

초기화를 수행하는 부분을 추가하면 다음과 같이 될것입니다.

main()
{
  const exam student("youngsoo", 90);
  student.memberprint();
 
  return 0;
}

student Object생성과 동시에 초기화 합니다. 이때 const선언도 같이 이루어 지도록 합니다.

위와 같은 내용으로 Program을 완성시켜 보겠습니다.

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
    int kuk;
 
  public:
    exam(char *nm, int i);
    void memberprint() const;
};

exam::exam(char *nm, int i)
{
  strcpy(name, nm);
  kuk = i;
}

void exam::memberprint() const
{
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
}

main()
{
  const exam student("youngsoo", 90);
  student.memberprint();
 
  return 0;
}


const에 대한 Member함수 접근


memberprint()는 const선언되었으므로 정상적인 처리 가능

'Programming > C C++' 카테고리의 다른 글

표준 Library 함수 - Memory 관련 함수  (0) 2011.06.16
[C, C++] Class구현시 생성자와 소멸자 활용  (0) 2011.06.01
[C, C++] Class  (0) 2011.05.25
[C, C++] cout 서식지정  (0) 2011.04.14
[C, C++] 구조체  (1) 2011.04.13
[C, C++] 변수선언및 초기화  (0) 2011.04.07
0 0
Programming/C C++
1. Data형

변수를 선언할때는 선언하고자 하는 변수가 어떤 Data를 얼마나 담을 수 있는지에 대한 형을 지정해 줘야 합니다. 이때 C에서 선언할 수 있는 정수와 실수의 Data형으로는 다음과 같은 종류가 있습니다.

 Data형  크기  실 표현 범위
 char  1  -128 ~ 127
 unsigned char  1  0 ~ 255
 int  4  -214783648 ~ 2147483647
 short int (16 bit)  2  -32768 ~ 32767
 long int (32 bit)  4  -214783648 ~ 2147483647
 unsigned int  4  0 ~ 4294967295
▶<1-1> 정수

 Data형  byte  실 표현 범위
 float  4  10-38 ~ 1038 (유효자리수 7자리)
 double  8  10-308 ~ 10308 (유효자리수 15자리)
 long double  -  10-4932 ~ 104932 (유효자리수 19자리)
▶ <1-2>실수

2. unsigned

unsigned는 특정 Data형에서 부호를 나타내는 bit를 수치로 나타내는 bit로 활용하는 것을 말합니다. 예를 들어 Char형 Data는 1byte크기로서 bit로 따지면 8bit가 됩니다.

00000000

그런데 맨앞의 1bit는 부호를 나타내는 bit이므로 실제 수치를 표현하는데 쓸 수 있는 bit는 뒤의 7bit뿐입니다. 이 7bit를 모두 1로 하고

01111111

10진수로 변환하면

127

이 됩니다. 결국 양수든 음수든 최대 127를 이상은 표현하지 못하는 것입니다.

여기서 맨앞의 1bit는 부호를 나타낸다고 하였는데 0일때는 양수, 1일때는 음수가 되므로 모두 1이 되었다고 가정한다면

11111111

-127 이 됩니다. 여기에서 상위 1bit를 부호가 아닌 unsigned를 통하여 수치로 환산하게 되면 255가 되므로 활용할 수 있는 Data형이 그 만큼 커지게 되는 것입니다.

참고:
부호를 나타내지 않을때는 unsigned를 쓴다고 하였는데 반대로 부호를 나타내고자 한다면 signed라고 써야합니다.(다만 생략이 가능한데 이 경우 기본값으로 signed가 사용됩니다.)

또한 unsigned는 Char형 뿐만 아니라 Int나 long형에도 동일하게 적용될 수 있습니다.

참고:
int는 long int와 같으므로 어떤걸 써도 차이는 없습니다. 다만 long int 라고 하기보다 줄여서 int로 하는 경우가 더 많습니다.

3. 수치자체에 Data형 지정하기

정수뒤에 u(U)를 붙이면 unsigned형을 l(L)을 붙이면 long형을 ul(UL)을 붙이면 unsigned long형 정수를 의미하게 됩니다.

12345u;
12345ul;

참고 :
위에서 처럼 u나 l르 반드시 붙여야만 되는 것은 아닙니다.(Compiler가 알아서 처리합니다.) 위 방식은 Program 작성시에 개발자가 눈으로 보기에 어떠한 성격의 Data형인지를 명확히 구분하기 위한 용도로 쓰입니다.

4. 단일 변수의 선언

보통 변수를 선언하는 방법은  'Data형 변수명'형식으로 하게 됩니다.

int a;

이때 같은 Data형일 경우 연속해서 선언할 수도 있습니다.

int a, b;

변수는 선언함과 동시에 초기화 하는 것도 가능합니다.

int a = 10;

정수가 아닌 문자는 문자상수 또는 수치상수를 이용하는 두가지 방법이 있습니다.

#include <stdio.h>

main()
{
  char c;

  c = 65; /* 수치 상수 */
 
  printf("%c\n", c);
 
  c = 'A'; /* 문자 상수 */
 
  printf("%c\n", c);
}



위와 같이 값을 대입하면 문자 'A'를 대입한 것과 같게 됩니다. 수치상수의 경우에는 ASCII값과 대응되어 값에 해당하는 문자가 표시되는 것입니다.

C에서 변수가 선언되면 특정 Memroy공간을 할당하게 되는데 이때 해당 변수에 대해서 초기화를 행하지 않으면 변수는 변수에 확보된 Memory의 Data값을 그대로 가지게 됩니다.

#include <stdio.h>

main()
{
  int i;
 
  printf("%d\n", i);
}


i변수를 선언한뒤 초기화 하지 않은채 i값을 출력하도록 하고 있습니다.


이때 출력되는 값은 i의 실제값이라기 보다는 변수 i가 위치하고 있는 Memroy의 값을 그대로 출력한 것입니다.(단, Static이나 전역변수는 0으로 자동 초기화 되며 배열 변수또한 초기화 하지 않으면 기본값은 0이 됩니다.)

#include <stdio.h>

int j;

main()
{
  static int i;
 
  printf("%d\n", i);
  printf("%d\n", j);
}


Static과 전역변수 확인


#include <stdio.h>

main()
{
  int i[2] = {1};
 
  printf("%d\n", i[0]);
  printf("%d\n", i[1]);
}


배열변수 i의 0번째 요소는 1로 초기화 하지만 1번째 요소는 초기화 하지 않습니다.


5. 배열 변수의 선언

배열은 []를 통해 나타냅니다. 이때 [와 ]사이에 배열의 크기를 지정하게 되는데 이때 배열의 순서는 0부터 시작하게 됩니다.

#include <stdio.h>

main()
{
  int i[2];
 
  i[0] = 123;
  i[1] = 456;
 
  printf("%d\n", i[0]);
  printf("%d\n", i[1]);
}


배열은 [2]라고 지정하여 총 2개 크기의 배열을 선언하였습니다. 두개의 배열이므로 배열의 순서는 0부터 1까지가 됩니다.(2까지가 아님을 주의하십시오. 0부터 2까지가 되려면 배열의 크기는 3이되야 합니다.)

배열의 선언 후 i[0] = 123; 등을 통해 각 요소에 값을 초기화 하고 printf()함수를 통해 배열의 값을 출력하도록 하고 있습니다.


위에서 배열은 i[0] = 123; 으로 i배열 [0]에 123이라는 정수값을 지정하였습니다. 이렇게 일일이 요소를 지정하여 값을 대입하는 대신 배열을 초기화 할 수 있는 별도의 방법을 이용하여 초기화 할 수도 있습니다.

int i[2] = {123, 456}; / * {} 괄호를 사용하여 배열을 초기화 합니다. */

즉 다음과 같이 하여도 결과는 같습니다.

#include <stdio.h>

main()
{
  int i[2] = {123, 456};

  printf("%d\n", i[0]);
  printf("%d\n", i[1]);
}


배열의 크기는 []괄호안에 나타내는데 만일 크기를 지정하기 힘든 경우라면 생략할 수도 있습니다.

int i[] = {123, 456};

이렇게 하게 되면 초기화 하는 값의 크기에 따라 자동으로 배열크기 2가 지정됩니다.

단, 이 생략의 경우 다차원 배열을 선언한 상태라면 가장 처음의 배열크기만 생략할 수 있습니다. 예를 들어

int i[][3] = {
    {1, 2, 3},
    {4, 5, 6}
  };

위와 같은 형태의 생략은 가능하지만

int i[2][] = {
    {1, 2, 3},
    {4, 5, 6}
  };

이렇게 생략하는건 불가능합니다.

지금까지 배열 선언시 1차원으로만 선언하였는데 배열은 필요하다면 다차원으로도 선언할 수도 있습니다.

int i[5][5];

[5][5]를 통하여 int형 변수 i배열을 2차원으로 선언하였습니다.

int i[5][5][5];

[5][5][5]를 통하여 int형 변수 i배열을 3차원으로 선언하였습니다.

이렇게 배열을 다차원으로 선언하면 그 만큼의 배열을 더 확보하게 됩니다. 예를 들어 int i[5][5];라고 했을때

i[0][0] 부터 i[0][4]까지 5개, i[1][0] 부터 i[1][4]까지 5개, i[2][0] 부터 i[2][4]까지 5개, i[31][0] 부터 i[3][4]까지 5개, i[4][0] 부터 i[4][4]까지 5개씩 총 25개의 배열를 확보하게 됩니다.

#include <stdio.h>

main()
{
  int i[5][5];
  i[3][2] = 100;
  i[4][1] = 200;

  printf("%d\n%d\n", i[3][2], i[4][1]);
}



다차원 배열의 초기화 방식도 1차원 배열의 초기화 방식과 크게 다르지 않습니다.

int i[2][3] = {1, 2, 3, 4, 5, 6};

다차원 배열을 초기화 하면 첫번째 첨자에 해당하는 배열부터 먼저 초기화 됩니다.(예를 들면 다음 순서처럼 [0][0]..[0][1]..[0][2]...[1][0]...[1][1]...)

다차원 배열을 초기화 할때는 아래경우 처럼 괄호({})를 중복하면

int i[2][3] = {
    {1, 2, 3},
    {4, 5, 6}
  };

배열초기화에 대한 구조를 좀더 알아보기 쉽도록 할 수 있을 것입니다.

주의:
만일 배열을 통한 Program개발시 배열의 범위를 넘어서는 경우가 있어도 Compiler는 Error를 발생하지 않습니다.

예를 들어

#include <stdio.h>

main()
{
  int i[2];
  i[5] = 100;

  printf("%d\n", i[5]);
}


이와 같은 Program의 경우 i배열크기로 2를 지정해놓고 100이라는 값을 i의 5번째배열에 저장하고 있습니다. 이 상태로 Program을 Compile하고 실행하면


잘 실행됨을 확인할 수 있습니다. 이런경우가 생기는 이유는 i[5]= 100;이라고 했을때 C는 배열의 크기를 고려하지 않은채 i배열의 5번째에 해당하는 Mmemory주소에 100이라는 값을 그대로 집어넣기 때문입니다.

하지만 이는 전혀 예상치 못한 Memory위치에 값을 써넣기 때문에 중대한 오류를 일으킬 수 있는 소지가 다분합니다. 따라서 반드시 배열을 사용할때는 그 크기를 잘 감안하도록 주의해야 합니다.

6. 배열을 이용한 문자열 다루기

문자열은 Char형 배열을 통해 다루게 됩니다. C에서는 문자열을 다루는 Data형은 존재하지 않기 때문에 Char형 Data를 배열화 하여 여러 문자를 결합함으로써 문자열을 표현합니다.

#include <stdio.h>

main()
{
  char s[6];
 
  s[0] = 'h';
  s[1] = 'e';
  s[2] = 'l';
  s[3] = 'l';
  s[4] = 'o';
  s[5] = 0;
 
  printf("%s\n", s);
}



여기서 맨 마지막 배열에 0을 추가한 이유는 C에서 '문자열의 끝은 0으로 표시한다.'라는 규칙이 존재하기 때문입니다. 문자열을 다룰때는 종종 문자열의 끝을 판단할 필요가 있는데 이런 경우 위와 같이 0으로 해당 문자열의 종료를 판단하곤 합니다.

따라서 실제 'hello'라는 문자열을 나타내는 경우 문자수는 5개이지만 문자열 끝을 나타내는 0이 필요하므로 실제 배열을 6개로 해야 합니다.

또한 문자열을 나타내는 문자배열도 일반 배열과 다를바 없으므로 다음과 같이 배열초기화 방법을 그대로 사용할 수 있습니다.

char s[6] = {'h', 'e', 'l', 'l', 'o', \0};

마지막 \0은 문자로서의 0이 아닌 문자열의 종료를 나타내기 위한 숫자 0임을 나타내기 위해서 입니다.

Char형 배열도 int형 배열처럼 다차원일 경우 {}를 통해 같은 방식으로 초기화 할 수 있습니다.

#include <stdio.h>

main()
{
  char s[2][6] = {
    {'h', 'e', 'l', 'l', 'o', '\0'},
    {'k', 'o', 'r', 'e', 'a', '\0'}
  };
 
  printf("%s\n", s[1]);
}



Char형으로 문자를 나타내기 위해서는 수치정수를 사용할 수 있으므로 다음과 같이 하여도 같은 결과를 나타내게 됩니다.

char s[5] = {104, 101, 108, 108, 111, 0};

배열 변수에 문자열을 대입하는 경우라면 문자열자체를 초기화 할 수 있는 방법이 별도로 존재합니다.

char s[6] = "hello";

위와 같이 하면 배열 s에 'hello'라는 문자열과 함께 문자열 종료를 의미하는 0도 같이 초기화 됩니다. 물론 이때에도 배열의 크기는 생략이 가능합니다.

char s[] = "hello";

문자배열도 다른 정수형태의 배열과 Data형만 틀릴뿐 별 차이가 없습니다. 따라서 초기화 할때도 배열의 크기에 맞지 않으면 나머지 부분은 0으로 자동초기화 됩니다.

#include <stdio.h>
main()
{
  char s[6] = "hell";
 
  printf("%s\n", s);
}


앞서 문자열의 끝은 0으로 판단한다고 하였습니다. 결국 s[4]에 0이 초기화 되어서 hell 문자열이 정상적으로 출력되고 있는 것입니다.

다차원 배열의 문자열 초기화 방식도 요소하나하나를 초기화 하는 것과 별반 차이가 없습니다.(단, 1차원 배열에서 문자열 초기화의 경우 {}를 사용하지 않은 것처럼 다차원도 {}를 사용하지 않고 ,만 사용됩니다.)

#include <stdio.h>
main()
{
  char s[2][6] = {
    "hello",
    "korea"
  };
 
  printf("%s\n", s[0]);
}


7. 변수의 이름 지정

변수의 이름은 비교적 자유롭게 작성할 수 있으나 꼭 지켜야할 몇몇 규칙이 존재합니다.

(1) 변수명은 영문대문자, 소문자, 밑줄, 숫자만 사용가능합니다.

(2) 변수명은 반드시 영문자나 밑줄로만 시작해야 합니다. 이때 숫자를 포함하는 변수명은 사용가능하지만 숫자로 변수명을 시작해서는 안됩니다.(숫자로 시작하는 경우 수치를 나타내는 정수로 인식될 수 있기 때문입니다.)

(3) 이름의 길이에는 제한이 없지만 처음부터 31문자 까지만 인식합니다. 즉, 31자를 넘어도 되지만 인식되는 이름은 31자 까지입니다.

(4) 변수명에서 대문자와 소문자는 구분됩니다.

(5) 예약어라는 것이 있습니다. C에서 쓰는 정해진 구문인데 이 예약어는 변수명으로 사용이 불가능 합니다.

auto, break, case, char, const, continue, default, do, double, else, enum, extern, float, for, goto, if, int, long, register, return, short, signed, sizeof, static, struct, switch, typedef, union, unsigned, void, volatile, while

다만 예약어를 포함하고 있는 전혀 새로운 문장의 경우에는 사용이 가능합니다. 예를 들어

autobicycle, doit

등 예약어를 포함한 전혀 다른 문장은 예약어와 충돌하지 않습니다.

8. Data형의 재정의

integer형의 변수선언은 int나 long int로 선언합니다.

int a;
long int a;

하지만 선언하고자 하는 Data형이 너무 길어서 쓰기 불편하거나 나만이 쓰는 다른 이름으로 대체하여 사용하고자 할때는 typedef를 통해 Data형의 이름을 다음과 같이 재정의 할 수 있습니다.

typedef long int l_int;

위와 같이 하면 l_int라고 했을때 long int를 사용한것과 같게 됩니다.

#include <stdio.h>

main()
{
  typedef long int l_int;
 
  l_int i;
 
  i = 100;
 
  printf("%d\n", i);
}



참고:
typedef는 얼핏 치환한다는 개념에서 #define와 비슷합니다만 #define는 전처리과정에서 해당 문자열을 치환할 뿐입니다. 반면 typedef는 Compiler에 의해 치환된다는 차이가 있습니다.

또한 typedef는 변수이외에 구조체등에도 사용할 수 있습니다. 자세한 설명은 다음 글를 참조하기 바랍니다.

[Develop/C, C++] - [C, C++] 구조체

9. const 상수


변수는 값이 변할수 있기 때문에 변수라고 합니다. 하지만 변수선언도 const를 동반하면 변수에 처음 값을 지정한 이후부터는 해당 변수값을 바꿀 수 없도록 할 수 있습니다.

#include <stdio.h>
main()
{
  const int i = 100;
 
  i = 200;
 
  printf("%d\n", i);
}


const를 사용하면 해당 변수의 값은 바꿀 수 없게 되며 만일 값을 바꾸려고 하는 시도가 있을 경우 Compil과정에서 오류를 발생하게 됩니다.


10. size_t

size_t는 가상Data형이라고 부르며 다른Data형과 구분되는 별도의 Data형이 아닌 typedef를 통해 unsigned int형으로 정의되어 있는 Data형입니다.

개인적인 견해로는 크게 쓸일이 없는 형입니다. size_t의 원래 목적은 C가 작동되는 여러 System안에서 같은 int형이라도 Data의 크기에 따라 Program이 틀어지는 문제를 해결하고자 호환성을 유지할 수 있도록 만들어진 것입니다.

하지만 현재에 와서는 큰 의미가 없습니다. 대부분의 Computer가 32bit이고(64bit로 발전해 가고 있는 추세) 또한 범위가 크다/작다를 따질만큼 빈약환 환경이 아니므로 빈번히 사용할 일은 없는듯 합니다.

#include <stdio.h>

main()
{
  printf("%d\n", sizeof(size_t));
  printf("%d\n", sizeof(int));



0 0
1
블로그 이미지

클리엘