Home [C++ 프로그래밍] 5강 - 클래스와 객체
Post
Cancel

[C++ 프로그래밍] 5강 - 클래스와 객체

💡해당 게시글은 방송통신대학교 이병래 교수님의 'C++ 프로그래밍' 강의를 개인 공부 목적으로 메모하였습니다.



학습 개요


  • 객체 지향 프로그래밍의 기본적 개념을 바탕으로 클래스를 선언하고 객체를 정의하여 사용하는 기본적인 구문에 대하여 학습
  • 클래스 선언문의 기본 형식과 클래스를 선언하기 위해 소스 파일을 구성하는 방법 등 프로그램 작성을 위한 기본적인 사항을 다룸
  • 생성자와 소멸자를 이용하여 객체가 생성될 때와 소멸될 때 처리해야 할 작업이 자동적으로 이루어지도록 프로그램을 작성하는 방법을 학습함



학습 목표


  • 데이터 멤버와 멤버 함수로 구성되는 클래스를 선언할 수 있음
  • 클래스 선언을 위해 필요한 소스 파일을 만들어 프로젝트를 구성할 수 있음
  • 생성자를 이용하여 객체 생성과 함께 초기화되도록 클래스를 선언할 수 있음
  • 소멸자를 이용하여 객체 소멸 과정에서 필요한 정리 작업을 수행할 수 있도록 클래스를 선언할 수 있음



주요 용어


  • 클래스(class)
    • 프로그램이 표현하고자 하는 대상(객체)이 어떠한 속성(데이터 멤버)을 저장하고 있어야 하고, 어떤 행위(멤버 함수)을 할 수 있는 가를 선언한 것
  • 객체(object)
    • 클래스의 실제 사례(instance)에 해당되며, 고유한 속성 값(데이터 멤버의 값)을 가지며, 이를 바탕으로 클래스에 정의된 행위를 할 수 있음
  • 캡슐화(encapsulation)
    • 객체 내부의 상세한 구현 부분과 사용자의 관점을 분리하는 것을 나타냄
    • 사용자는 객체의 내부 요소를 직접 사용할 수 없으며, 공개된 인터페이스를 통해 객체를 사용함
  • 생성자(constructor)
    • 객체가 생성될 때 수행할 작업을 정의하는 특수한 멤버 함수로, 객체의 초기화 작업을 수행함
  • 소멸자(destructor)
    • 객체가 소멸될 때 수행할 작업을 정의하는 특수한 멤버 함수로, 객체가 가지고 있는 자원을 반납하는 등의 처리를 담당함



강의록


클래스 선언과 객체 정의

객체

  • 객체(object)란?
    • 소프트웨어 시스템 안의 어떠한 대상을 표현한 것으로
      • 정해진 처리를 수행할 수 있음
        • 행위, 메소드, 멤버 함수
      • 처리 과정에 따라 내부 상태가 변화할 수 있음
        • 속성, 데이터 멤버
      • 다른 객체와 상호 작용 할 수 있음
        • 메시지 전달(멤버 함수 호출)

    image.png

클래스

  • 클래스(class)란?
    • 객체의 설계도
    • 객체가 포함할 데이터 멤버의 선언과 멤버 함수의 정의를 포함함

    image.png

클래스 선언

  • 클래스 선언문의 형식

    1
    2
    3
    4
    5
    6
    7
    8
    
      class ClassName {
      가시성_지시어_1:
        데이터 멤버 선언;
        멤버함수 선언; // 원형 선언 또는 멤버 함수 정의
      가시성_지시어_2:
        데이터 멤버 선언;
        멤버함수 선언; // 원형 선언 또는 멤버 함수 정의
      };
    
  • 가시성 지시어
    • 클래스의 멤버가 공개되는 범위를 나타냄
    • 종류
      • private, public, protected
    • 공개 범위

      가시성 지시어공개 범위
      private (디폴트)소속 클래스의 멤버 함수
       친구 클래스의 멤버 함수 및 친구 함수
       그 외의 범위에는 비공개
      public전 범위
    • 용도

      가시성 지시어용도
      private (디폴트)정보 은닉을 위해 사용됨
       클래스의 구현을 위한 내부 상태(데이터 멤버)는 일반적으로 private으로 지정함
      public주로 외부에 제공할 인터페이스를 공개하기 위해 사용됨
  • 캡슐화(encapsulation)
    • 객체 내부의 상세한 구현 부분과 외부 사용자의 관점을 분리함

      image.png

      • 내부 속성 등 구현에 대한 부분은 공개하지 않으며(정보 은닉), 객체 외부에서는 공개된 인터페이스를 통해 객체를 사용할 수 있음

클래스의 예 - Counter클래스

  • Counter클래스
    • 계수기를 나타내는 클래스를 선언하라.
    • 계수기 객체는 값을 0으로 지울 수 있고, 값을 1씩 증가 시킬 수 있으며, 현재의 계수기 값을 알려줄 수 있다.

    image.png

  • 행위

    멤버함수비고
    void reset()계수기의 값을 0으로 지움
    void count()계수기의 값을 +1 증가 시킴
    int getValue()계수기의 현재 값을 알려 줌
  • 속성

    Counter
    -value: int
    +reset(): void
    +count(): void
    +getValue(): int

Counter 클래스의 선언 - Counter.h

1
2
3
4
5
6
7
8
9
10
#ifndef COUNTER_H_INCLUDED
#define COUNTER_H_INCLUDED

class Counter { // 클래스 Counter의 선언 시작
    /**
    * Counter의 멤버 선언
    **/
};

#endif // COUNTER_H_INCLUDED

객체의 정의 및 사용

  • 객체 정의 형식

    1
    2
    
      ClassName objName;
      ClassName objName1, objName2, ······;
    
    • ex)

      1
      2
      3
      4
      
        int main()
        {
            Counter c1, c2;
        }
      
  • 객체 사용 형식

    • 객체 이름에 멤버 선택 연산자(.)를 사용하여 객체의 멤버를 액세스함
    1
    2
    
      cin >> objName.dataMember;
      objName.memFunc( );
    
    • 객체의 멤버 함수 안에서 그 객체에 속한 멤버를 사용할 때는 멤버 이름만으로 액세스함
    • ex)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      
        class Counter {
            int value;
                  
        public:
            void reset()
            { value = 0; }
                  
            void count()
            { ++value; }
                  
            int getValue() const
            { return value; }
        };
      
      1
      2
      3
      4
      5
      
        int main() {
            Counter c;
            c.reset();
            c.count();
        }
      

Counter 객체의 정의 및 사용 - CntMain.cpp

  • private멤버 접근하기 때문에 오류 발생

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
      #include <iostream>
      #include "Counter.h"
      using namespace std;
        
      int main()
      {
          Counter cnt; // Counter 객체의 정의
          cnt.value = 0; // 계수기를 0으로 지움
          cout << "계수기의 현재 값 : " << cnt.value << endl;
          cnt.value++; // 계수기를 1 증가시킴
          cnt.value++;
          cout << "계수기의 현재 값 : " << cnt.value << endl;
          return 0;
      }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
      class Counter {
          int value;
            
      public:
          void reset()
          { value = 0; }
            
          void count()
          { ++value; }
            
          int getValue() const
          { return value; }
      };
    
  • 올바른 사용 법

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
      #include <iostream>
      #include "Counter.h"
      using namespace std;
        
      int main()
      {
          Counter cnt; // Counter 객체의 정의
          cnt.reset(); // 계수기를 0으로 지움
          cout << "계수기의 현재 값 : " << cnt.getValue() << endl;
          cnt.count(); // 계수기를 1 증가시킴
          cnt.count();
          cout << "계수기의 현재 값 : " << cnt.getValue() << endl;
          return 0;
      }
    
    cnt:Counter
    -value ?
    cnt:Counter
    -value 0
    cnt:Counter
    -value 1
    cnt:Counter
    -value 2

const멤버 함수

  • 데이터 멤버의 값을 수정하지 않는 멤버 함수
    • Counter.h

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      
        class Counter {
            int value;
        public:
            void reset()
            { value = 0; }
                  
            void count()
            { ++value; }
                  
            int getValue() const
            { return value; }
        };
      
    1
    2
    3
    
      const Counter c;
      int n = c.getValue(); // OK!
      c.count(); // 오류
    
    • Counter.h

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      
        class Counter {
            int value;
        public:
            void reset()
            { value = 0; }
                  
            void count()
            { ++value; }
                  
            int getValue()
            { return value; }
        };
      
      1
      2
      3
      4
      5
      
        void f(Counter& c)
        {
            c.count();
            cout << c.getValue();
        }
      
      • 오류

        1
        2
        3
        4
        
          void g(const Counter& c)
          {
              cout << c.getValue();
          }
        
    • Counter.h

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      
        class Counter {
            int value;
        public:
            void reset()
            { value = 0; }
                  
            void count()
            { ++value; }
                  
            int getValue() const
            { return value; }
        };
      
      1
      2
      3
      4
      5
      
        void f(Counter& c)
        {
            c.count();
            cout << c.getValue();
        }
      
      1
      2
      3
      4
      5
      
        void g(const Counter& c)
        {
            cout << c.getValue();
      
        }
      

소스 파일의 구성

image.png

생성자

생성자

  • 생성자(constructor)
    • 객체가 생성될 때 수행할 작업을 정의하는 특수한 멤버 함수
    • 생성자에 인수를 전달할 수 있도록 매개 변수를 선언할 수 있음
    • 생성자를 여러 개 다중정의할 수 있음
  • 생성자의 특성
    • 클래스의 이름을 사용하여 선언함
    • 생성자 머리에 반환 자료형을 표시하지 않으며, return명령으로 값을 반환할 수 없음
    • 생성자를 public으로 선언해야 클래스 외부에서 객체를 생성할 수 있음
  • 생성자 선언 형식

    1
    2
    3
    4
    5
    6
    7
    8
    
      class ClassName {
        
      public:
          // 생성자
          ClassName(fParameterList){
              // 객체 생성을 위한 준비 작업
          }
      };
    

생성자의 예 - Counter클래스

  • Counter.h (생성자 없는 버전)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
      class Counter {
          int value;
            
      public:
          void reset()
          { value = 0; }
            
          void count()
          { ++value; }
            
          int getValue() const
          { return value; }
      };
    
    • CntMain.cpp

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      
        int main()
        {
            Counter cnt;
            cnt.reset();
            cout << "계수기의 현재 값 : " << cnt.getValue() << endl;
            cnt.count();
            cnt.count();
            cout << "계수기의 현재 값 : " << cnt.getValue() << endl;
            return 0;
        }
              
      
      cnt:Counter
      -value 0
  • Counter.h (생성자 있는 버전)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
      class Counter {
          int value;
      public:
          Counter()
              { value = 0; }
            
          void reset()
              { value = 0; }
            
          void count()
              { ++value; }
            
          int getValue() const
              { return value; }
      };
    
    • CntMain.cpp

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      
        int main()
        {
            Counter cnt;
            // cnt.reset();
            cout << "계수기의 현재 값 : " << cnt.getValue() << endl;
            cnt.count();
            cnt.count();
            cout << "계수기의 현재 값 : " << cnt.getValue() << endl;
            return 0;
        }
      
      cnt:Counter
      -value 0

초기화 리스트

  • 초기화 리스트
    • 생성자의 머리에 데이터 멤버를 초기화하는 값들을 나열한 리스트
    • 데이터멤버이름{초깃값}형태로 초깃 값을 지정
  • Counter.h

    1
    2
    3
    4
    5
    
      class Counter {
          int value;
      public:
          Counter() : value{0} { } // 생성자
      };
    

소멸자

소멸자

  • 소멸자(destructor)
    • 객체가 소멸될 때 수행할 작업을 정의하는 특수한 멤버 함수
  • 소멸자의 특성
    • 클래스의 이름에 ~를 붙여 선언함
    • 소멸자 머리에 반환 자료형을 표시하지 않으며, return명령으로 값을 반환할 수 없음
    • 매개 변수가 없으며, 클래스에 하나의 소멸자만 정의할 수 있음
    • public으로 선언하는 것이 일반적임
    • 상속을 통해 파생 클래스를 정의하는 경우 virtual을 지정하여 가상 함수가 되도록 하는 것이 좋음
  • 소멸자 선언 형식

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
      class ClassName {
        
      public:
        ClassName(fParameterList) { // 생성자
          // 객체 생성을 위한 준비 작업
        }
          
        ~ClassName() { // 소멸자
          // 객체 제거를 위한 정리 작업
        }
      };
    

Person클래스의 명세

  • Person클래스
    • 사람을 나타내는 클래스를 선언하고자 한다. 사람 객체는 ‘···에 사는 ···입니다.’라고 자신을 알릴 수 있으며, 주소를 변경할 수 있다.
  • 행위

    멤버 함수비고
    Person(char* name, char* addr)생성자
    ~Person()소멸자
    void print()‘···에 사는 ···입니다’ 라고 출력함
    void chAddr(char* newAddr)주소를 변경함
  • 속성

    데이터 멤버비고
    char* name이름을 저장함
    char* addr주소를 저장함

Person 클래스의 선언 - Person.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef PERSON_H_INCLUDED
#define PERSON_H_INCLUDED

class Person { // 클래스 Person의 선언 시작
  char* name; // 이름을 저장하는 데이터멤버
  char* addr; // 주소를 저장하는 데이터멤버

public: // public 멤버함수
  Person(const char* name, const char* addr); // 생성자
  ~Person(); // 소멸자
  void print() const; // 이름과 주소 출력
  void chAddr(const char* newAddr); // 주소 변경
};

#endif // PERSON_H_INCLUDED

Person 클래스의 선언 - Person.cpp

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>
#include <cstring>
#include "Person.h"
using namespace std;

Person::Person(const char* name, const char* addr)
{
  // 이름을 저장할 공간 할당
  this -> name = new char[strlen(name) + 1];
  // 데이터 멤버 name에 이름을 복사
  strcpy(this -> name, name);
  // 주소를 저장할 공간 할당
  this ->addr = new char[strlen(addr) + 1];
  // 데이터 멤버 addr에 주소를 복사
  strcpy(this -> addr, addr);
  cout << "Person 객체 생성함(" << name << ")" << endl;
}

Person::~Person() // 소멸자
{
  cout << "Person 객체 제거함(" << name << ")" << endl;
  delete[] name; // 이름 저장공간 반납
  delete[] addr; // 주소 저장공간 반납
}

void Person::print() const
{
  cout << addr << "에 사는 " << name << "입니다." << endl;
}

void Person::chAddr(const char* newAddr)
{
  delete[] addr; // 기존 공간 반납
  // 새로운 주소에 맞는 공간 할당
  addr = new char[strlen(newAddr) + 1];
  strcpy(addr, newAddr); // 데이터멤버 addr에 새로운 주소를 복사
}

Person 클래스의 선언 - PrsnMain.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include "Person.h"
using namespace std;
int main()
{
  Person* p1 = new Person("이철수", "서울시 종로구");
  Person* p2 = new Person("박은미", "강원도 동해시");
  
  p1->print();
  
  p2->print();
  cout << endl << "주소 변경 : ";
  p2->chAddr("대전시 서구");
  p2->print();
  delete p1;
  delete p2;
  return 0;
}

  • 출력 화면

    1
    2
    3
    4
    5
    6
    7
    8
    
      Person 객체 생성함(이철수)
      Person 객체 생성함(박은미)
      서울시 종로구에 사는 이철수입니다.
      강원도 동해시에 사는 박은미입니다.
        
      주소 변경 : 대전시 서구에 사는 박은미입니다.
      Person 객체 제거함(이철수)
      Person 객체 제거함(박은미)
    



연습 문제


  1. 다음 중 클래스 선언문에서 정보 은닉을 위해 사용되는 가시성 지시어는?

    a. private

    • 클래스의 구현을 위한 내부 상태인 데이터 멤버는 일반적으로 private으로 지정하며,정보 은닉을 위해 사용됨
    • 외부에 제공할 인터페이스로 공개하기 위해서는 public으로 지정함
  2. 위 지문의 클래스 선언문에서 멤버 함수 memF1()의 몸체 (가)에서 사용할 수 있는 문장은?

    1
    2
    3
    4
    5
    6
    7
    8
    
     class ClassA {
       int a, b;
     public:
        
       int memF1() const {
       // (가)
       }
     };
    

    a. return a * b;

    • 멤버 함수 memF1()const멤버 함수로 선언되었으므로, 함수 내에서 데이터 멤버 a나 b에 대해서는 값을 읽을 수만 있고 값을 변경하는 문장은 사용할 수 없음
  3. 위 지문의 클래스 선언문에서 const키워드를 넣는 것이 바람직한 곳을 모두 나열한 것은?

    1
    2
    3
    4
    5
    6
    7
    8
    
     class Counter {
         int value;
     public:
         Counter() // ___(ㄱ)___ {value = 0;}
         void reset() // ___(ㄴ)___ {value = 0;}
         void count() // ___(ㄷ)___ {++value;}
         int getValue() // ___(ㄹ)___ {return value;}
     };
    

    a. ㄹ

    • 데이터 멤버의 값을 수정하지 않는 멤버 함수에 대하여 const를 지정함
  4. 위 지문의 클래스에서 객체가 생성될 때 데이터 멤버 x가 0으로 초기화되도록 공란에 생성자를 선언한 것으로 적절한 것은?

    1
    2
    3
    4
    5
    6
    
     class ClassB {
         int x;
     public:
         // ______
        
     };
    

    a. ClassB() : x{0} {  }

    • 생성자는 클래스의 이름과 같고 결과 값을 반환하지 않으며, 이러한 경우 일반 함수에서는 함수의 머리 부에 반환 자료형을 void로 표기하나, 생성자의 경우는 이마저도 표기하지 않음
    • 함수의 몸체에서는 x에 0을 대입하는 문장을 사용하거나, 초기화 리스트를 이용하여 x를 초기화함
  5. 위 지문은 ClassA의 선언문 일부이다. 소멸자의 머리부 ㈀에 넣을 적절한 내용은?

    1
    2
    3
    4
    5
    6
    7
    8
    
     class ClassA {
         int x;
     public:
        
         // __(ㄱ)__
         {  }
        
     };
    

    a. ~ClassA()

    • 소멸자는 클래스의 이름에 ~를 붙인 이름을 사용하며, 인수를 전달 받을 수 없음
    • 또한 return명령으로 값을 반환 할 수 없으며, 일반 함수처럼 void라고 표기하지도 않음



정리 하기


  • 클래스는 프로그램이 표현하고자 하는 대상(객체)이 어떠한 속성(데이터 멤버)를 저장하고 있어야 하고, 어떤 행위(멤버 함수)를 할 수 있는 가를 선언한 것임
  • 클래스에 해당 되는 실제 사례(instance)를 객체(object)라고 함
    • 객체는 고유한 속성 값(데이터 멤버의 값)을 가지며, 이를 바탕으로 클래스에 정의 된 행위를 할 수 있음
  • 가시성 지시어 private, public, protected는 클래스의 멤버가 공개 되는 범위를 지정하기 위해 사용 되는데, 정보 은닉을 위해 private을, 외부에 제공할 인터페이스를 공개하기 위해 public을 사용함
  • 클래스에서 데이터 멤버의 값을 변경하지 않는 멤버 함수는 const멤버 함수로 정의
  • 생성자는 객체가 생성 될 때 수행하는 작업을 정의하는 특수한 멤버 함수로서, 클래스 이름과 동일한 이름으로 선언하며, 일반적으로 객체를 초기화 하는 작업을 수행함
  • 소멸자는 객체가 소멸 될 때 수행할 작업을 정의하는 특수한 멤버 함수로, 클래스 이름과 동일한 이름 앞에 ~를 붙여 선언하며, 객체가 가지고 있는 자원을 반납하는 등의 처리를 담당함

[C++ 프로그래밍] 4강 - 함수

[C++ 프로그래밍] 6강 - 클래스와 객체