C++ 클래스와 관련한 내용을 작성한다.


의미 정의

클래스 = 멤버변수 + 멤버함수

클래스(Class) = 속성(Attribute) + 방법, 기능(Method)

  • ​ 데이터 추상화(Data Abstraction) : 사물을 기능적, 데이터적 측면으로 재정의 하는 것
  • ​ 클래스화 : 추상화된 데이터를 통해 사용자 정의 자료형을 정의하는 것(클래스화)

_ 1

객체(Object): 클래스를 이용하여 정의된 자료형의 변수

  • ​ 인스턴스화(instantiation, 객체화) : 클래스를 기반으로 객체를 생성하는 것

_ 2

클래스 멤버 접근

내부, 외부 접근

. 내부 접근 : 같은 클래스 내에 존재하는 멤버에 의한 접근

. 외부 접근 : 내부 접근 외의 모든 접근

Public, Protected, Private

. Public : 클래스 외부 접근 허용

. Private : 클래스 내부 접근만 허용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>

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

const int OPEN=1;
const int CLOSE=2;

class Door{
    private:
        int state;
    public:
        void Open(){
            state = OPEN;   // 내부 접근
        }
        void Close(){
            state = CLOSE;  // 내부 접근
        }
        void ShowState(){
            cout << "현재 문 상태 :";
            cout << ((state==OPEN)? "OPEN" : "CLOSE") << endl; 
        }
};

int main(){
    Door d;
    // d.state = OPEN;      // 외부 접근(private라 접근 불가) - 오류 발생

    d.Open();               // 외부 접근
    d.ShowState();          // 외부 접근
    
    return 0;
}

멤버 함수 외부 접근 및 인라인(inline)

. 외부 접근은 :: 연산자를 활용함

인라인

. 함수 선언, 혹은 정의 앞에 inline 키워드를 함수의 앞단에 추가

. 컴파일된 함수 코드가 프로그램의 코드 안에 직접 삽입됨

​ : 성능의 향상이 가능함

​ : 메모리 사용 측면에서 인라인 함수가 일반 함수보다 불리

​ : 자료형에 독립적이지 못함

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>

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

const int OPEN=1;
const int CLOSE=2;

// ****** Door 클래스 `선언` ****** //
class Door{
    private:
        int state;
    public:
        void Open();        
        void Close();
        void ShowState();        
};
// ****** Door 클래스 `선언` ****** //

// ****** Door 클래스 멤버 함수 `정의` ****** //
void Door::Open(){
    state = OPEN;   // 내부 접근
}
void Door::Close(){
    state = CLOSE;  // 내부 접근
}
void Door::ShowState(){
    cout << "현재 문 상태 :";
    cout << ((state==OPEN)? "OPEN" : "CLOSE") << endl; 
}

// 함수를 인라인 하기 위해서는, inline 키워드를 붙여주면 됨
// ex) void Door::Open() -> inline void Door::Open()
// ****** Door 클래스 멤버 함수 `정의` ****** //

int main(){
    Door d;
 
    d.Open();
    d.ShowState();
    
    return 0;
}

정보은닉(Information Hiding)

일반적으로, 객체의 외부에서 객체 내에 존재하는 멤버 변수에 직접 접근을 허용하지 않도록 함

. 클래스 선언 시, public, private 등의 선언을 하지 않고, 멤버 변수를 정의하면 private 가 기본으로 설정됨

. 아래 예제와 같이, 멤버 변수의 접근을 멤버 함수로 제한하고, 함수 안에서 조건을 따지는 형태로 구성하는 것으로 보임

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>

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

class Point
{
    // public, private를 지정하지 않으면 private가 기본으로 설정됨
    int x;  // x 좌표 범위 0-100
    int y;  // y 좌표 범위 0-100    

    public:
        int GetX(){return x;}
        int GetY(){return y;}

        void SetX(int _x);  // == void SetX(int);
        void SetY(int _y);  // == void SetY(int);    
};

void Point::SetX(int _x){
   if(_x < 0 || _x > 100) // 경계 검사
   {
       cout << "잘못된 X 좌표 입력" << endl;
       return;
   }
   x = _x;              // 정보 은닉 형태, 클래스 멤버 변수에 대한 내부 접근만 허용
}

void Point::SetY(int _y){
   if(_y < 0 || _y > 100) // 경계 검사
   {
       cout << "잘못된 Y 좌표 입력" << endl;
       return;
   }
   y = _y;              // 정보 은닉 형태, 클래스 멤버 변수에 대한 내부 접근만 허용   
}

int main(){
    int x, y;
    cout <<"좌표값 입력: ";
    cin >> x >> y;

    Point p;
    p.SetX(x);
    p.SetY(y);

    cout << "입력 값 문제 없음" << endl;

    return 0;
}

1

캡슐화(Encapsulation)

관련 있는 데이터와 함수를 하나의 단위로 묶음

생성자(Constructor) 및 소멸자(Destructor)

객체 생성의 2 단계 : 메모리 할당 → 생성자 호출

생성자는 객체 생성 시 원하는 값으로 초기화 하기 위해 사용됨

생성자 내에서 메모리를 동적 할당하는 경우, 이를 해제하기 위해서 반드시 소멸자를 정의해야 함

특징

  • 함수
  • 클래스의 이름과 같은 이름
  • 리턴 타입 선언 없음
  • 리턴 값 없음
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include <string.h>		// strcpy 사용하기 위한 헤더파일

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

const int SIZE=20;

class Person{
    char name[SIZE];
    char phone[SIZE];
    int age;

    public:        
  		Person(char * _name, char* _phone, int _age);
        void ShowData();
};

Person::Person(char * _name, char* _phone, int _age)
{
    strcpy(name, _name);    
    strcpy(phone, _phone);
    age = _age;
}

void Person::ShowData()
{
    cout << " name : " << name << endl;
    cout << " phone : " << phone << endl;
    cout << " age : " << age << endl;    
}

int main()
{
    Person p("ABC", "010-123-4567", 30);		// 객체 생성 동시에, 초기화 가능
    // Person p = ("ABC", "010-123-4567", 30); 의 형태로도 생성 가능
    p.ShowData();

    return 0; 
}

3

Default 생성자

  • 생성자를 정의 하지 않으면 기본(Default) 생성자가 자동 삽입됨

  • 생성자도 함수이므로 오버로딩 가능

  • 생성자도 함수이므로 기본(Default) 매개 변수의 설정이 가능

_ 1

. 기본적으로 Default 매개 변수를 지정한 생성자 구성을 활용하도록 함

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>

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

class Point
{
    int x, y;
    public:
  	   Point();							
       Point(int _x, int _y);
       void ShowData(); 
};

Point::Point(){							// 생성자도 함수 오버로딩 가능
  	x=y=0;
}

Point::Point(int _x=0, int _y=0)        // 생성자에 Default 매개 변수 지정
{
    x = _x;   y = _y;
}
void Point::ShowData()
{
    cout << x  << "  " << y << endl;
}

int main()
{
    Point p1(10, 20);
    p1.ShowData();

    Point p2; // Default 생성자를 호출할 경우, Default 매개 변수가 지정되어 있어
              // 오류가 발생하지 않음
              // Default 매개 변수가 지정이 안되어 있을 경우, Default 생성자를 찾을 수 없어 오류 발생             
    p2.ShowData();
}

1

멤버 이니셜라이져(Member initialization list, 멤버 초기화 리스트)

. 생성자의 역할인 멤버 초기화를 수행함

. ` : ` 연산자를 활용하여 구현함

. 객체 생성 이전에 초기화가 이루어진다

사용해야할 상황
  1. default 생성자 없을 때
  2. 클래스가 레퍼런스를 멤버로 가질 때
  3. 상수 멤버를 초기화 할 때
  4. 생성자 파라미터의 이름이 데이터 멤버와 같을 때
  5. 부모 클래스의 멤버변수 초기화(상속)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
......
class Point
{
  	private:
  		int x;
  		int y;
  	public:
  	// 일반적 초기화(생성자)
    /*
    point(int _x, int _y){
          x = _x;
          y = _y;
    }
    */
  
  	// 멤버 이니셜라이져
  	point(int _x, int _y): x(_x), y(_y){}  
};
.......

Default 소멸자

객체 소멸의 2 단계 : 소멸자 호출 → 메모리 해제

객체를 소멸시키기 전, 할당된 메모리를 해제하는 등의 일련의 과정을 수행하기 위함

  • 함수

  • ~ 연산자가 클래스 이름 앞에 붙은 형태로 선언

  • 리턴타입 선언 없음

  • 리턴 값 없음

  • 매개 변수 없음

  • 오버로딩 불가

  • Default 매개 변수 선언 불가

  • 소멸자를 정의 하지 않으면 기본(Default) 소멸자가 자동 삽입됨

일반적으로, 생성자 내에서 동적 할당을 수행하는 경우, 이를 해제하기 위해 반드시 소멸자를 정의해야 함
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <string.h>

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

class Person{
    char * name;
    char * phone;
    int age;

    public:
        Person(char * _name, char* _phone, int _age);
        ~Person();			// 소멸자
        void ShowData();
};

Person::Person(char * _name, char* _phone, int _age)
{
  	// new 연산자 이용한 메모리 동적할당
    name = new char[strlen(_name) + 1];
    strcpy(name, _name);    

    // new 연산자 이용한 메모리 동적할당
    phone = new char[strlen(_phone) + 1];
    strcpy(phone, _phone);
    age = _age;
}

Person::~Person()
{
    // delete 연산자 이용한 메모리 할당 해제
    delete [] name;
    delete [] phone;
}

void Person::ShowData()
{
    cout << " name : " << name << endl;
    cout << " phone : " << phone << endl;
    cout << " age : " << age << endl;    
}

int main()
{
    Person p("ABC", "010-123-4567", 30);
    p.ShowData();

    return 0; 
}

3

. 위 예제의 경우, 메모리 동적할당 형상

_ _ 2

클래스 배열

객체 배열

객체 배열이 생성되기 위해서는 void 생성자의 호출이 요구됨

객체 포인터 배열1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>

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

class Point{
    int x;
    int y;

    public:
        Point(){
            cout << "Default Constructor!" << endl;
            x=y=0;
        }
        Point(int _x, int _y){
            x= _x;
            y= _y;
        }        

        int GetX(){ return x; }
        int GetY(){ return y; }
        void SetX(int _x) { x = _x; }
        void SetY(int _y) { x = _y; }
};

int main(){
    Point * arr[5];		// 포인터 배열(배열 요소로 포인터를 가짐)을 선언

    for(int i=0; i<5; i++)
    {
        arr[i] = new Point( i*2, i*3);	// 메모리 동적 할당 후, 객체 포인터 할당
  		// i*2, i*3 을 인자(정수형)로 받을 수 있는 Point 클래스 생성자 호출하면서, Point 객체 생성
    }
    for(int j=0; j<5; j++)
    {
        cout << " x: " << arr[j]->GetX() << " ";
        cout << " y: " << arr[j]->GetY() << endl;
    }
	
  	// 할당된 메모리 해제
    for(int k=0; k<5; k++)
    {
        delete arr[k];
    }

    return 0;
}

4

this 포인터

. 자기 참조 포인터

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>

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

class Data{
    int a;
    int b;

    public:
        Data(int a, int b){		// 클래스 멤버 변수와 Data()함수의 매개변수의 이름이 같음
            // a = a;			// 이 경우, 클래스 멤버 변수의 값을 변경할 수 없음
            this->a = a;
            // b = b;
            this->b = b;
        }
        void ShowData(){
            cout << a << " " << b << endl;
        }
};

int main(void)
{
    Data d(10, 20);
    d.ShowData();

    return 0;
}

5

friend 선언

. private로 선언된 멤버변수에 대해 외부 접근을 허용하는데 사용됨

. friend 선언은 단방향성 특성을 지님

_ 1

_ 2

전역 함수에 대한 friend 선언

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>

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

class counter{
    int val;
    public:
        counter(){
            val = 0;            
        }
        void Print() const{
            cout << val << endl;
        }
        friend void SetX(counter& c, int val);    
};

void SetX(counter& c, int val)
{
    c.val = val;
}

int main()
{
    counter cnt;
    cnt.Print();

    SetX(cnt, 2000);
    cnt.Print();
    return 0;
}

12

클래스에 대한 friend 선언

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
using std::cout;
using std::endl;

class First{
    private:
        int data;
        friend class Second;
    public:
        First(){
            data = 0;
        }
        void Print(){
            cout << data << endl;
        }
};

class Second{
    public:
        void SetData(First& first, int val){
            first.data = val;   // class First의 private 영역 접근
        }        
};

int main()
{
    First first;
    Second second;

    first.Print();

    second.SetData(first, 200);

    first.Print();

    return 0;
}

13

  1. 포인터 배열은 배열 요소로 포인터를 가짐, ‘배열 포인터’ 는 주로 2,3차원 배열에서 배열을 가리키기 위한 포인터를 지칭 

태그:

카테고리:

업데이트: