'Class'에 해당되는 글 3건

Programming/C C++
 클래스와 개체

클래스는 int나 float와 같이 또 하나의 자료형으로 취급될 수 있습니다. 다만 그 자료형을 개발자가 만든다는 것에 차이가 존재합니다. 따라서 클래스는
int a;
처럼 메모리상에 위치할 실체인 객체형의 인스턴스를 생성해서 사용해야 하고 이때 생성된 인스턴스가 바로 개체에 해당하는 것입니다. 즉, 클래스를 자료형으로 하고 그에 맞는 변수(객체)를 생성하는 것과 같습니다.

 클래스 선언

C++에서 클래스는 다음의 형식으로 작성됩니다.
class MyClass
{
    멤버 변수;
    멤버 함수;
};

함수와는 다르게 클래스는 끝에 ; 문자가 붙는다는 점에 주의하십시오. MyClass는 클래스의 이름으로서 적절하게 개발자가 정하면 됩니다.

클래스 안에 여러 변수와 함수를 구현하여 실제 클래스를 정의하며 클래스 안에 포함된 변수나 함수를 클래스의 멤버라고 합니다. 다음은 클래스 작성의 예입니다.

class MyClass
{
    int d;

    void day(int a)
    {
        d = a;
    }
};
 접근제한자

클래스의 멤버에는 외부에서 접근이 가능한지 여부를 정할 수 있는 제한자가 존재합니다. 제한자로는 public, private, protected 세가지가 있는데 멤버에 특정한 제한자를 설정하지 않는 경우에는 기본적으로 private 형으로 취급됩니다.

public 접근자는 클래스 외부에서 해당 멤버에 대한 접근을 자유롭게 하며 private는 클래스 내부와 friend외에는 접근이 불가능하도록 합니다. protected는 private과 비슷하지만 추가적으로 클래스를 상속받은 파생클래스에서만 접근할 수 있습니다.
class MyClass
{
public:
    void day(int a)
    {
        d = a;
    }

private:
    int d;
};
위에서 처럼 public이 설정된 day 함수는 외부에서 접근이 가능하지만 private이 지정된 멤버변수 d에는 외부에서 접근할 수 없습니다.
MyClass myclass;
myclass.day(30);
 인라인 멤버함수 정의

위의 모든 예제에서는 멤버함수를 정의할때 클래스 내부에서 멤버함수를 정의하였습니다.

class MyClass
{
public:
    void day(int a)
    {
         d = a;
    }

private:
    int d;
};
클래스를 정의하는 방법은 위와 같은 방법 말고도 클래스 내부에서 멤버함수를 선언하고 외부에서 해당 함수를 정의하는 방법이 있습니다.
class MyClass
{
public:
    void day(int a);

private:
    int d;
};

void MyClass::day(int a)
{
    d = a;
}
클래스 내부에서는 day함수에 대한 선언만 되어 있고 외부에서 day함수가 구체적으로 어떠한 처리를 하는지 정의되어 있습니다.

멤버함수 정의부분에서는 MyClass라는 클래스 이름으로 :: 라는 범위지정자를 통해 day함수가 MyClass클래스 소속의 멤버함수라는 것을 알려주고 있습니다. 이렇게 하지 않으면 외부에서 정의된 멤버함수가 어떤 클래스에 소속되어야 하는지에 대한 모호한 문제가 생길 수 있습니다.

참고로 정의 정의 부분에는 클래스 내부에 있는 변수 d에 값을 대입하도록 되어 있는데 변수 사용시 클래스 내부가 아닌 전역적으로 선언된 변수라면 '::d' 처럼 지정하여 해당 변수가 전역변수임을 알려야 합니다.

컴파일러는 위와 같이 선언되고 정의된 함수에 대해서는 해당 함수호출부분이 발견되면 호출 코드를 아예 함수실행코드로 치환해 버립니다. 이러한 처리 방법은 함수호출에 대한 오버헤드를 감소함으로서 프로그램의 수행속도를 빠르게 하지만 프로그램자체의 크기는 커지는 단점이 있습니다.

통상 프로그램의 크기가 커지면 프로그램을 메모리에 로드하고 실행시키기 까지 시간이 더 오래 걸릴 수 있습니다.

 정적멤버

일반적인 클래스멤버는 클래스에 대한 인스턴스 생성시에 비로소 메모리에 올라오고 인스턴스 레벨에서 해당 멤버에 접근이 가능해지게 됩니다.

반면 정적멤버는 프로그램 실행시에 처음부터 메모리에 위치하게 되고 인스턴스 생성이 필요 없이 바로 클래스 레벨에서 접근이 가능하며 프로그램이 종료되어야 메모리에서 해제되는 특징이 있습니다.

int d;

class MyClass
{
public:
    static void day(int a)
    {
         ::d = a;
    }

private:
    static int i;
};
어떤 멤버함수를 정적멤버화 하려면 멤버선언 앞에 static라고만 붙여주면 됩니다. 그러면 클래스 레벨에서 해당 멤버로 접근할 수 있습니다.
//MyClass myclass; -> 인스턴스 생성이 필요없음
 MyClass::day(30);
그런데 멤버함수가 아닌 멤버변수가 정적멤버로 지정된 경우에는 인스턴스를 생성한다 해도 메모리에 로드되지 않습니다. 정적멤버와 객체는 다른 메모리 공간을 사용하기 때문인데 다음과 같이 클래스 외부에서 정적멤버변수에 대한 초기화를 수행해 줘야 합니다.
int MyClass::i = 0;
위 초기화는 특정 함수내부나 클래스 내부가 아닌 변수 d 처럼 외부에 나와 있어야 합니다.

 생성자와 소멸자

클래스의 생성자는 클래스의 개체가 생성될때 호출되며 반대로 소멸자는 개체가 소멸될때 호출되는 함수입니다.

클래스의 생성자와 소멸자는 다음과 같은 형식으로 작성됩니다.
class 클래스명
{
    클래스명(); // 생성자
    ~클래스명() // 소멸자
};

클래스 이름과 같은 함수명을 작성하면 그 함수가 생성자가 되며 앞에 ~문자를 추가하면 소멸자가 됩니다. 다만 생성자와 소멸자는 클래스를 생성할때마다 붙여줄 필요가 없는데 이런 경우 컴파일러가 기본 생성자와 소멸자를 알아서 붙여주게 됩니다.

class MyClass
{
    int i;

    MyClass(int a)
    {
         i = a;
    }
};

위 예제에서 처럼 생성자를 오버로딩하면 클래스 내부의 멤버변수 값을 초기화 하거나 그외 기타 필요한 작업을 수행할 수 있습니다.

여기서 멤버변수는 생성자 이외에도 초기화 라는 구현을 통해 멤버변수를 초기화 할 수 있습니다.

class MyClass
{
    int i;

    int x;

    MyClass(int a);
};

MyClass::MyClass(int a) : x(10)
{
    i = a;
}
위 예제에서는 함수정의 부분에서 : x(10) 을 통해 멤버변수 x에 대한 초기값을 설정해 주고 있습니다. 직접 변수에 값을 주는 방법 이외에도 매개변수로 초기값을 설정해 줄 수도 있습니다.
MyClass::MyClass(int a) : x(a) //매개변수 a의 값으로 멤버변수 x를 초기화
{
    i = a;
}
 상속

특정 클래스에 대한 상속을 구현하면 해당 클래스의 멤버함수와 멤버변수를 물려받을 수 있습니다. 이때 물려받는 자식클래스를 파생클래스(Derived Class), 물려주는 부모클래스를 기반클래스(Base Class)라고 합니다.
class BaseClass
{
};
위와 같은 형태의 기반클래스가 있다고 가정할 경우 이를 상속받는 파생클래스를 구현하려면 다음과 같이 작성합니다.
class DerivedClass : [접근한정자] BaseClass
{
};
이 예제에서 기반클래스는 BaseClass가 되며 파생클래스는 DerivedClass가 됩니다. [접근한정자] 부분은 클래스를 상속받을때 어떤 유형으로 멤버를 상속받을지를 나타내는 부분으로서 아래 중 하나를 사용할 수 있습니다.

 public  기반클래스의 public와 protected 멤버를 그대로 상속받습니다.
 protected  기반클래스의 public와 protected를 protected로 상속받습니다.
 private  기반클래스의 public와 protected를 private로 상속받습니다.

만약 파생클래스의 객체가 생성되는 경우 기반클래스의 생성자가 우선적으로 호출되고 그 다음 파생클래스의 객체를 호출하게 됩니다. 물론 반대의 경우에는 파생클래스의 소멸자를 우선으로 호출하고 뒤이어 기반클래스의 소멸자를 호출합니다.

class BaseClass
{
public:
 BaseClass();
 int mValue;
};

BaseClass::BaseClass() : mValue(10)
{
 cout << "1 - value : " << mValue << endl;
}

class DerivedClass : public BaseClass
{
public:
 void valuePrint();
};

void DerivedClass::valuePrint()
{
 cout << "2 - value : " << mValue << endl;
}

int main()
{
 DerivedClass dc;
 dc.valuePrint();

 return 1;
}
위 코드는 클래스의 상속과 생성자 호출 순서를 확인해 보는 예제입니다. 한가지 더 알려드릴건 파생클래스는 다음과 같이 여러 기반클래스로 부터 상속받을 수 있는데
class DerivedClass : public BaseClass1, public BaseClass2, ....
{
public:
 void valuePrint();
};
이때의 생성자 호출 순서는 기반클래스를 작성한 순서(public BaseClass1, public BaseClass2, ....
)에 따르게 되며 반대로 종료될때는 맨뒤에 지정된 클래스(BaseClass2)의 소멸자부터 순서대로 호출됩니다.

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

[Visual C++] 배열  (3) 2012.10.10
[Visual C++] 복사생성자  (0) 2012.10.09
[Visual C++] 클래스(Class) 의 기본  (5) 2012.10.08
[Visual C++] 연산자 오버로딩(Operator Overloading)  (0) 2012.10.05
[Visual C++] 포인터와 참조  (2) 2012.07.12
[Visual C++] typedef  (0) 2012.07.06
5 0
Programming/C C++
Class사용시에는 Class의 Object를 생성한 후 각 Member함수를 호출하여 Member변수의 값을 설정합니다.

이와는 달리 Class의 생성자는 Object생성과 동시에 원하는 Member변수를 초기화 할 수 있습니다.

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

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

exam::exam(char *nm, int k, int m, int e)
{
  strcpy(name, nm);
 
  kuk = k;
  mat = m;
  eng = e;
}

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("young soo", 90, 100, 80);
 
  student.memberprint();
  return 0;
}


Class안에 exam(char *nm, int k, int m, int e); 으로 생성자를 선언하고 main안에서 exam student("young soo", 90, 100, 80); 구문을 통해 생성자로 초기값을 설정합니다.

생성자의 선언은 Class이름과 동일하게 하고 인수를 설정하여 어떠한 Member에 값을 설정할지를 지정하면 됩니다. 생성자의 본체도 Class이름으로 다음과 같이 작성되어 해당 Member에 대해 초기화를 수행하도록 합니다.
exam::exam(char *nm, int k, int m, int e)
{
  strcpy(name, nm);
 
  kuk = k;
  mat = m;
  eng = e;
}

생성자는 초기화 전용입니다. 따라서 return을 통해 값을 반환할 수 없습니다. 반환값없는 전용이므로 이 생성자함수에 void나 int처럼 return형식을 지정하는 것 자체가 무의미한 것입니다.

생성자를 통해 값을 초기화 하려면 Class의 Object생성시 바로 인수를 건네주도록 합니다. 그러면 자동으로 생성자가 호출되어 해당 Class에 대한 초기화처리를 하게 됩니다.

exam student("young soo", 90, 100, 80);

소멸자는 Class이름앞에 ~문자를 붙여 선언하는 것으로 이 소멸자는 Class의 Member함수를 호출하고 그 함수를 빠져나올때 자동으로 호출되는 특징을 가지고 있습니다.

#include <iostream.h>
#include <string.h>
class exam{
  private:
    char name[15];
 
  public:
    exam(char *nm);
    ~exam();
   
    void name_input(char *nm);
    void memberprint();
};

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

exam::~exam()
{
  cout << "소멸자가 호출됨" << endl;
}

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

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

main()
{
  exam student("young soo");
 
  student.memberprint();
  return 0;
}


Class안에 ~exam();으로 소멸자를 선언하였습니다. 이 소멸자는 Class내의 함수가 호출되고 난 후마다 자동 호출됩니다.


소멸자는 어떤값도 반환하지 않고 또 어떠한 인수도 전달하지 않습니다. 또한 소멸자를 정의하는 함수부분에는 개발자가 Class의 함수호출이 이루어지고 난 다음에 필요한 부분을 작성하기만 하면 되는 것입니다.

1. 생성자 Overloaded

C++에서의 함수는 Overloaded가 가능합니다. 즉, 같은 이름의 함수에 다른 인수의 특성에 따라 다른처리를 행하는 것이 가능한 것입니다.

이러한 Overloaded는 일반 함수뿐만 아니라 생성자에도 적용할 수 있습니다. 물론 생성자에 Overloaded를 선언하는 방법도 일반함수와 다를게 없습니다.

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

class exam{
  private:
    char name[15];
    int kuk;
    int mat;
    int eng;
 
  public:
    exam();
    exam(char *nm, int k, int m);
    exam(char *nm, int k, int m, int e);
   
    void memberprint();
};

exam::exam()
{
  strcpy(name, "noname");
 
  kuk = 0;
  mat = 0;
  eng = 0;
}

exam::exam(char *nm, int k, int m)
{
  strcpy(name, nm);
 
  kuk = k;
  mat = m;
  eng = 200;
}

exam::exam(char *nm, int k, int m, int e)
{
  strcpy(name, nm);
 
  kuk = k;
  mat = m;
  eng = e;
}

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

main()
{
  exam student_fir;
  student_fir.memberprint();
 
  exam student_sec("young soo", 90, 100);
  student_sec.memberprint();
 
  exam student_thr("soo young", 90, 100, 50);
  student_thr.memberprint();
  return 0;
}


Class에서 exam세개를 선언하였으며 각각의 함수마다 인수를 틀리게 하여 Overloaded화 하였습니다. Class에서 생성자를 Overloaded로 선언하면 각 함수에 맞는 정의도 다음과 같이 해주어야 합니다.

exam::exam()
{
  strcpy(name, "noname");
 
  kuk = 0;
  mat = 0;
  eng = 0;
}

exam::exam(char *nm, int k, int m)
{
  strcpy(name, nm);
 
  kuk = k;
  mat = m;
  eng = 200;
}

exam::exam(char *nm, int k, int m, int e)
{
  strcpy(name, nm);
 
  kuk = k;
  mat = m;
  eng = e;
}


이렇게 하면 생성자를 호출할때마다 해당 인수에 따라서 다른 형태로 초기화를 수행할 것입니다.

주의할 것은 Class의 Object를 생성할때 다른 Overloaded 생성자를 호출하고자 한다면 다음과 같이 다른 이름의 Object를 사용해야 한다는 것입니다.

exam student_fir;
student_fir.memberprint();
 
exam student_sec("young soo", 90, 100);
student_sec.memberprint();
 
exam student_thr("soo young", 90, 100, 50);
student_thr.memberprint();


만일 Class의 Object가 배열로 생성되면 []를 이용해 몇번째 배열의 Object에서 Member를 호출할지를 지정해야 하는데 이때 위와 같은 생성자의 특징을 이용하면 {}를 사용해 배열의 Member를 한꺼번에 초기화 할 수도 있습니다.

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

class exam{
  private:
    char name[15];
    int kuk;
    int mat;
    int eng;
 
  public:
    exam(char *nm, int k, int m, int e);
   
    void memberprint();
};

exam::exam(char *nm, int k, int m, int e)
{
  strcpy(name, nm);
 
  kuk = k;
  mat = m;
  eng = e;
}

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

main()
{
  exam student[2] = {
    exam("soo young", 90, 100, 50),
    exam("young soo", 59, 65, 88)
  };
 
  student[0].memberprint();
  student[1].memberprint();
  return 0;
}


exam Class의 student Object를 2로 하여 2개의 배열로 Object가 생성되도록 하였습니다.

이후 초기화는 {와 }사이에 묶어 exam("soo young", 90, 100, 50)과 exam("young soo", 59, 65, 88)으로 각각의 배열에 이름과 점수를 초기화 합니다.

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

[Visual C++] 관련 라이브러리  (0) 2012.06.21
표준 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
0 0
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
1
블로그 이미지

클리엘