[강좌 : 객체지향 - 4] 추상화
2009.08.10 17:00
김성용(topmentor)
http://cafe.naver.com/gisdev/475  
4. 추상화
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><?xml:namespace prefix = o /><?xml:namespace prefix = o /><?xml:namespace prefix = o /> 
   가. 개 요
지난 시간에 설명한 대로 추상화라고 하는 것은 객체들의 공통적인 특징(속성과 기능)을 뽑아내는 것입니다. 구현하는 객체들이 가진 공통적인 데이터와 기능을 도출해 내는 것을 의미한다고 강조했습니다.
 
그리고 데이터의 추상화와 기능의 추상화를 설명하면서 추상화라고 하는 것에는 항상 새로운 이름이 붙는다는 공통점이 있고 프로그래밍 입장에서 추상화라고 하는 것은 ‘공통의 속성이나 기능을 묶어 이름을 붙이는 것’으로 정리하였습니다. 기억이 나시나요?
 
이번 시간에는 객체지향 프로그래밍 입장에서 추상화를 다루어 보도록 하겠습니다. 간단합니다. 클래스를 정의하는 과정이 바로 추상화입니다.
 
여기서 잠깐 복습하나 해 보죠? 클래스가 왜 필요하죠? …
네. 우리가 프로그램 상에서 사용할 실체는 객체인데 이 객체를 만들기 위해서는 틀이 필요합니다. 좀 시스템 적으로 들어가면 객체를 활용하려면 메모리상의 자원으로 적재되어야 하는 데 언어가 기본적으로 제공하는 type이 아니면 메모리에 적재할 수 없습니다. 즉, 정의하지 않았거나 미리 약속되지 않은 것은 메모리에 적재할 수 없다는 것입니다. 따라서 이미 약속된 것이 아니라면 하나의 type으로 정의해야 한다는 것입니다. 예를 들어 언어가 기본적으로 제공하지 않는 기능은 함수라는 것을 만들어야 쓸 수 있습니다. (실행시에는 함수도 메모리에 적재됩니다.) 그리고 언어가 제공하지 않은 새로운 데이터형은 구조체나 typedef등의 방법으로 새로운 type을 만든 후 그 type에 대한 변수를 생성할 수 있습니다. (변수 생성은 메모리상에 변수 영역이 할당됨을 의미합니다.)
 
객체도 마찬가지 입니다. 객체가 가진 속성데이터와 기능을 정의하지 않고는 메모리에 올릴 수 없습니다. 그 객체 생성을 위한 type이 바로 클래스입니다. 그래서 객체가 중심이 되는 객체지향 프로그래밍에서는 클래스가 핵심이 될 수 밖에 없습니다.
 
 
 
   나. 추상화 하는 방법
     1) 클래스 정의
클래스를 정의하는 방법부터 살펴 볼까요? 객체지향 프로그래밍 개요에서 객체지향 프로그래밍은 프로그램을 위해 활동할 객체를 정의하고 이들간에 인터페이스를 정의한다고 했습니다. 그 기억을 떠올리면서 클래스를 정의하는 단계를 보시기 바랍니다. 아래와 같습니다.
 
    첫번째 단계, 해결하려는 구축하려는 시스템 혹은 문제에 대한 것을 자연어로 기술한다. (문제기술)
           가급적 자세히 기술하는 것이 좋다.
    두번째 단계, 문제 기술로 부터 명사들을 뽑아낸다.
    세번째 단계, 명사들중에서 객체가 될 수 있는 명사와 객체가 지니는 속성이 되는 명사를 구분해 낸다.  
           속성 데이터에 대한 추상화라고 할 수 있음.
    네번째 단계, 문제 기술에서 동사에 주목해서 객체의 기능이 될 수 있는 부분을 추출해 낸다.
        이 부분이 바로 객체의 기능을 추상화하는 것임. 만약 기능을 추가 과정에서 필요한 데이터가 있으면
        멤버 변수로 추가할 수 있다.
        (이것을 설계멤버라고 합니다. 추상화에 의해 얻어진 속성 데이터와 구분하기 위한 것입니다.)
    다섯째 단계, 추상화된 데이터(속성)과 기능을 하나의 형(Type)으로 정의한다. (클래스로 정의)
 

 
    <?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><?xml:namespace prefix = v /><?xml:namespace prefix = v /><?xml:namespace prefix = v />
위 그림을 보면 문제기술로부터 객체 후보를 뽑아내고 이들의 공통적인 특징을 추상화하고 있습니다. 공통의 속성 (이름, 성별, 나이, 고향)과 공통의 기능(패를 낸다, 패를 뒤집는다, 광을 팔고 쉰다, 패를 계산한다)을 도출하여 ‘GIS과정학생’이라는 클래스를 정의하고 있습니다.
 
추상화를 통해 클래스를 정의할 때 몇가지 고려할 사항이 있습니다. 첫째, 도출한 객체 후보(명사들)들을 클래스로 만들 것인가? 아니면 속성데이터로 넣을 것인가?를 결정해야 합니다. 단순히 변수하나로 처리하면 될 것을 일부러 클래스로 만들어 복잡하게 처리할 필요가 없습니다.
 
둘째, 구현에 필요한 속성인가?를 결정해야 합니다. 구현에 필요하지도 않은 속성을 열심히 끌어 붙이는 것은 메모리 낭비일 뿐만 아니라 코드만 복잡해집니다. 위 그림의 예를 보면 ‘이름’이라는 공통의 속성이 있지만 이것이 프로그램 수행에 아무 역할도 못한다면 과감히 배제하는 것이 낫습니다. 여기에는 일정한 답이 존재하지 않습니다. 추가, 배제에 대한 판단은 구현하려는 시스템이나 서비스에 초점을 두어 판단하면 됩니다.
         
 

    2) 인스턴스화 : 정의된 클래스로 부터 객체를 생성해 내는 것.
인스턴스는 만들어진 클래스로부터 생성된 객체입니다. 인스턴스란 원래 어떤 틀로부터 찍어낸 메모리상의 실체를 통칭해서 말합니다. (윈도우 프로그래밍에서도 인스턴스란 용어가 나옵니다.) 좀 어렵나요? 
int a;
라는 코드에서 a는 int 타입의 인스턴스라고 볼 수 있습니다. 따라서 인스턴스는 클래스 타입의 변수로 생각하면 될 것 같습니다.
 
          
 
위 그림을 보면 ‘GIS과정학생’이라는 클래스로 이세돌, 한도리, 김만수라는 객체를 만들고 있습니다. 바로 이들이 인스턴스입니다.
 
  

다. 클래스의 정의
 이 부분은 간단한 문법만 살펴보고 넘어가겠습니다. 원래 C++강좌가 아니라 객체지향 강좌이기 때문에 여기서 길게 설명을 이어가는 것은 낭비라는 판단입니다.
 
     1) 클래스 선언 및 정의 문법 (C++기준)
        - 형태
        class 클래스이름 {
          (멤버접근지정) :
            멤버 변수 선언;
           멤버 함수 선언;
        }
        리턴형 클래스이름::멤버함수명(인자..)
        {
         // 구현 부분            
        }
 
         ex) class Point {
              private :
                  int xPosition;
                  int yPosition;
              public:
                  void move(int x, int y);
          }
 
          void Point::move(int x, int y)
          {
                xPosition += x;
                yPosition += y;
           }
 
         * 대개 클래스 정의 부분은 헤더 파일(.h) 에, 멤버함수에 대한 구현 부분은
         .cpp파일에  하는 것이 일반적이다
 
 
     2) 멤버변수와 멤버 함수 정의
         클래스 내부에 속해있는 데이터와 함수를 멤버라고 합니다. 이 멤버에는 2종류가 있습니다.
         첫째, 추상화 멤버 가 있는 데 이것은 추상화를 통해 얻어진 멤버를 일컫습니다.
         둘째, 설계 멤버 는 클래스와 의미상 관계는 없으나 프로그램 개발의 필요에 의해
            (특히 함수 구현에 있어 필요한 경우) 개발자가 임의로 만든 멤버를 말합니다.

         ‘멤버’를 지칭하는 용어가 여러가지 있는 데 언어에 따라 조금씩 다른 용어가 쓰이고 있으니 참조하기 바랍니다.
 
일반정의
Data(변수)
Procedure(함수)
학술적정의
State
Behavior
VB, Smalltalk,
Object Pascal
Attribute
Method
C++
Member 변수
Member 함수
Java
Field
Method
        
    
   3) 멤버들의 특징
      멤버들의 사용에 앞서 한 가지 정확하기 인지할 것이 있습니다. 객체의 사용대상은 객체 자체라기 보다는 객체가 가진 멤버라는 것입니다. 즉, 객체단위의 연산이나 조작은 별로 없습니다. 대부분 객체의 멤버를 대상으로 데이터를 입출력하고 함수를 호출합니다. 일반적으로 멤버에 대한 접근은 아래와 같은 문법을 따릅니다.
 
    객체이름.멤버
    ex) MyCar.speed = 1;
       MyCar.speedUp();
 
다음은 멤버함수와 멤버변수의 특징입니다.
 
      - 멤버 함수
         . 멤버변수는 모든 멤버함수를 통해 공유된다.
         . 멤버변수를 아무 제약없이 멤버 함수에서 사용할 수 있다.
 
      - 멤버변수
         . 객체를 생성해야 사용가능.
         cf. 멤버변수 선언과 동시에 초기화 하는 것은 C++에서는 문법적 오류로 본다.
          => 콜론 초기화를 이용하거나 생성자에서 초기화 한다.
          class MyClass
          {
              int a=10;               // 에러
          };
        
 
 
4) 인스턴스 생성
인스턴스를 생성하는 방법은 크게 2가지가 있습니다. 정적인 방법으로 생성하는 것과 동적인 방법을 생성하는 것이 있는 데 이것은 C++에서만 그렇고 요즘 대표적인 객체지향 언어인 자바나 C#의 경우는 동적인 방법으로만 객체를 생성할 수 있습니다.(이 방식이 더 객체지향적이라고 봅니다.) 일단 아래 설명은 C++을 기준으로 합니다.
 
         가) 정적할당 방법으로 객체 생성
          1- 클래스 객체 생성 (인스턴스)
              ex) Car myCar;
          2- 객체 사용
             : 구조체와 마찬가지로 멤버접근 지정자(.)를 사용한다.
              ex) myCar.velocity = 10;        // 멤버변수
                myCar.speedDown();    // 멤버함수
          - 정적 할당된 객체는 Stack에 저장영역이 만들어 집니다. 그런데 Stack에 만들어진 객체들의
           멤버 변수들을 자동 초기화 되지 않으므로 생성자에서 꼭 초기화 해 주어야 합니다.
 
         나) 동적할당 방법으로 객체 생성
           1- 클래스 객체에 대한 포인터 변수 정의 
              ex) Car *myCar;
           2- 클래스 객체 생성 (인스턴스)
              ex) myCar = new Car;
           3- 객체 사용
              : 포인터에 의한 멤버 접근 연산자(->) 사용
              ex) myCar->velocity = 10;       // 멤버 변수
                 myCar->speedDown(); // 멤버 함수
           4- 객체 사용이 끝나면 동적 할당한 객체를 해제 해야 한다.
              ex) delete myCar;
            - 동적 할당된 객체는 Heap에 만들어 지므로 프로그램이 끝날 때까지 메모리 영역이 남아있
             게 됩니다. 따라서 객체 사용이 끝나면 필히 delete 시켜 주어 메모리에서 해제를 해주어야
             합니다. 자바나 C#의 경우는 가비지 컬렉션을 통해 생성한 객체를 자동으로 해제 시켜 줍니
             다.

+ Recent posts