블로그 이미지
하루, 글. 그림. 영상매체. 표현을 도와주는 기기들. 도전 중. 동화다아아
    동화다아아

    카테고리

    분류 전체보기 (176)
    잡담 (1)
    IT 기기-리뷰&뉴스 (7)
    리뷰 - 도서 (1)
    리뷰 - 영상 (0)
    리뷰 - 그림/음악 (1)
    내장형 하드웨어 (163)
    Total
    Today
    Yesterday

    - 구조체 안에 함수를 사용할 수 있는 것의 발전되어 클래스가 되었다.
     → C++은 일반 구조체에서도 함수를 사용할 수 있다.(C에서는 불가능)

    - 객체는 데이터 위주(예제의 OBJ를 함수로 둘러싼다.)
     → 구조적 프로그램은 자료와 함수가 분리되어 있고, 자료에 쉽게 접근하게 된다.(자료에 대한 보호가 부실)
     → 객체는 자료에 대해 일괄적인 인터페이스를 제공하고 사용용도를 유도할 수 있다.
     → 예제

    #include<iostream.h>
    #include<stdlib.h>


    struct emb
    {
      int *item;
      int iNum;  
      
      // 구조체 초기화 함수
      bool embInit(emb *stVal)
      {  
        // 분홍색 값은 리터럴(문자상수)이다.
        if(0 == stVal) // Null 을 입력받으면
        {
          return false;
        }
        stVal->item = 0;
        stVal->iNum = 0;
        cout << "embInit" << endl;

        return true;
      }
      // 구조체 메모리 할당
      bool embInit(emb *stVal, unsigned int uiNum)
      {
        // 분홍색 값은 리터럴(문자상수)이다.
        if(0 == stVal) // Null 을 입력받으면
        {
          return false;
        }
        else if(0 == uiNum)
        {
          return false;
        }
        // item에 동적 할당
        stVal->item = (int *)malloc(sizeof(int)*uiNum);
        // 동적 할당을 못 받았을 경우
        if(0 == stVal->item)
        {
          return false;
        }
        stVal->iNum = uiNum;
        cout << "embInit" << endl;
      
        return true;
      }
      // 구조체 메모리 초기화 함수
      void embFree(emb *stVal)
      {
        if(0 == stVal)
        {
          return ;
        }
        if(0 == stVal->item)
        {
          return ;
        }
        free(stVal->item);
        stVal->item = 0;
        stVal->iNum = 0;
        cout << "embFree" << endl;
        return ;
          
      }  
    };
    int main()
    {
      emb OBJ;
      // 자료의 추상화
      // OBJ에 함수만이 접근하고 main()은 접근하지 않는다.
      // 즉, 함수를 통해서 간접적으로 건드리게 하는데
      // 이것을 OBJ가 추상화 되었다. 자료가 추상화 되었다고 한다.
      OBJ.embInit(&OBJ); // 0으로 초기화 하는 함수
      OBJ.embInit(&OBJ, 300); // 동적할당 및 전체 계수(1200byte)
      OBJ.embFree(&OBJ);
      
      return 0;
    }

    → 실행 결과

     → 위와 같이 구조체에 함수를 추가하여도 잘 동작 하는 것을 확인할 수 있다.
     → 위에서 함수는 구조체 내에 있으므로 인자로 받을 필요 없이 구조체 내의 변수를 사용할 수 있으므로 인자를 제거한다.
     → 소스를 바꾸어 보면

    #include<iostream.h>
    #include<stdlib.h>


    struct emb
    {
      int *item;
      int iNum;  
      
      // 구조체 초기화 함수
      bool embInit()
      {  
        // 분홍색 값은 리터럴(문자상수)이다.
        item = 0;
        iNum = 0;
        cout << "embInit" << endl;

        return true;
      }
      // 구조체 메모리 할당
      bool embInit(unsigned int uiNum)
      {
        if(0 == uiNum)
        {
          return false;
        }
        // item에 동적 할당
        item = (int *)malloc(sizeof(int)*uiNum);
        // 동적 할당을 못 받았을 경우
        iNum = uiNum;
        cout << "embInit" << endl;
      
        return true;
      }
      // 구조체 메모리 초기화 함수
      void embFree()
      {
        free(item);
        item = 0;
        iNum = 0;
        cout << "embFree" << endl;
        return ;
          
      }  
    };
    int main()
    {
      emb OBJ;
      // 자료의 추상화
      // OBJ에 함수만이 접근하고 main()은 접근하지 않는다.
      // 즉, 함수를 통해서 간접적으로 건드리게 하는데
      // 이것을 OBJ가 추상화 되었다. 자료가 추상화 되었다고 한다.
      OBJ.embInit(); // 0으로 초기화 하는 함수
      OBJ.embInit(300); // 동적할당 및 전체 계수(1200byte)
      OBJ.embFree();
      
      return 0;
    }

     → 실행 결과

     → 같은 실행결과를 얻었다.
     → 인자로써 변수가 필요없어 불필요해진 코드들을 삭제함으로 써 소스의 양이 줄었다.
     → 오버로딩을 객체지향에서는 다향성이라고 한다.
     → 여기에 기능을 추가해서 클래스를 만든다.

     → 구조체는 메모리에 없다. 위의 소스에서 메모리에 올라간 것은 OBJ
     → 예를 들어 붕어빵과 틀을 생각해 보면 틀은 클래스 붕어빵은 객체(OBJ)이다.
     → 클래스의 관점에서는 붕어빵은 같고 객체의 관점에서는 다르다.
     → 즉, 인간이라는 카테고리를 클래스라 보면 각각의 우리는 서로 다른 객체이다.

     → 클래스를 만들 때 모델링을 한다. 모델링은 정의를 내리는 것이다.
     → 속성(attribute)
     ※ cmd 창에서 attrib 이라고 치면 해당 폴더 내의 파일 속성을 보여준다.


     → 머리색, 피부색은 상태(status)정보, 동작은 행위(behavior) 정보
     → 모든 속성은 상태와 행위(행동)을 가진다. 이를 위해 클래스는 변수 + 함수를 가지며 이를 통해 정보를 가진다.
     → 클래스를 만든다는 것은 분류한다는 것을 뜻한다.

     → 접근 속성
     → 위의 예제에서 struct를 class로 바꾸어 주고 
     → 변수는 private: , 함수는 public: 을 붙여주고 들여쓰기를 한뒤 컴파일 하면 에러없이 컴파일 한다.
     → 기본적으로 모든 속성은 private 이다. 이것은 클래스 안에서는 모두 사용할 수 있다.
     → public은 외부에서 접근이 가능하다.
    #include<iostream.h>
    #include<stdlib.h>


    class emb // emb 클래스를 부른다.
    {
      private :
        int *item;
        int iNum;  

      public :
        bool embInit();
        bool embInit(unsigned int uiNum);
        void embFree();
    };
    int main()
    {
      emb OBJ;
      OBJ.embInit(); // 0으로 초기화 하는 함수
      OBJ.embInit(300); // 동적할당 및 전체 계수(1200byte)
      OBJ.embFree();
      
      return 0;
    }
    // 스코프 연산자를 붙인다.
    bool emb::embInit()
    {  
      item = 0;
      iNum = 0;
      cout << "embInit" << endl;
      return true;
    }
    bool emb::embInit(unsigned int uiNum)
    {
      if(0 == uiNum)
      {
        return false;
      }
      item = (int *)malloc(sizeof(int)*uiNum);
      iNum = uiNum;
      cout << "embInit" << endl;

      return true;
    }
    void emb::embFree()
    {
      free(item);
      item = 0;
      iNum = 0;
      cout << "embFree" << endl;

      return ;
    }


     → 일반적으로 속성끼리 모아 쓰며, 변수 함수끼리도 각각 모아 쓴다.
     → 클래스 내부에는 변수와 함수 선언만 있는 것이 바람직 하다.
     → 따라서 함수부분을 클래스에서 빼고 함수 선언만 넣어 둘 수 있는데 그냥 컴파일 하면 문제가 발생한다.
     → 왜냐하면 클래스의 밖에 있는 함수의 본체는 클래스 내부에 선언된 함수 원형과는 다르기 때문이다. 따라서 에러가 발생한다.
     → 이를 해결하기 위해서는 함수 본체의 이름 앞에 emb:: 를 붙여줘야 한다.(클래스 이름::)
     → 이렇게 하면 클래스 내부에 선언한 함수 원형이 밖에 있는 함수의 본체를 가리키는 것이 된다. (JAVA는 이 방법이 되지 않으며 클래스 내부에 함수 본체를 넣어야 한다.)

     → 다음으로 위의 예제를 각각 emb.h, emb.cpp, main.cpp 3개의 파일로 분리한다. 

    #ifndef __EMB_H_
    #define __EMB_H_

    #include
    <iostream.h>
    #include<stdlib.h>

    class emb // emb 클래스를 부른다.
    {
      
    private :
        
    int *item;
        
    int iNum;  

      
    public :
        
    bool embInit();
        
    bool embInit
              (
    unsigned int uiNum);
        
    void embFree();
    };

    #endif

    #include"emb.h"

    // 스코프 연산자를 붙인다.
    bool emb::embInit()
    {  
      item 
    = 0;
      iNum 
    = 0;
      cout 
    << "embInit" << endl;
      
    return true;
    }
    bool emb::embInit(unsigned int uiNum)
    {
      
    if(0 == uiNum)
      {
        
    return false;
      }
      item 
    = (int *)malloc
                  (
    sizeof(int)*uiNum);
      iNum 
    = uiNum;
      cout 
    << "embInit" << endl;

      
    return true;
    }
    void emb::embFree()
    {
      free(item);
      item 
    = 0;
      iNum 
    = 0;
      cout 
    << "embFree" << endl;

      
    return ;
    }

    #include<iostream.h>
    #include<stdlib.h>
    #include"emb.h"

    int main()
    {
      emb OBJ;
      OBJ.embInit(); 
    // 0으로 초기화 하는 함수
      OBJ.embInit(300); // 동적할당 및 전체 계수(1200byte)
      OBJ.embFree(); // 메모리 해제
      
      
    return 0;
    }


     → 위와 같이 파일을 나누어 컴파일 할 수 있다.
     → 보통 클래스는 헤더 파일(emb.h) 함수는 함수끼리 모아서(emb.cpp), 그리고 메인 함수(main.cpp)로 구분한다.


    - inline (사용법, 특징)
     → 함수의 이름 앞에 inline을 붙일 수 있다.
     → inline bool emb::embInit() 이라고 사용
     → 이렇게 사용하면 원래는 main에서 호출될때 사용하는 함수의 본체가 main함수 안으로 직접 써지게 된다.
     → 따라서 실행파일의 크기가 커지나 실행속도가 빨라진다.
     → 클래스 안에서는 inline을 사용하지 않는다. 클래스 안에서 함수를 만들면 자동 inline 되기 때문.
     → 따라서 inline 함수는 무조건 헤더 파일에 들어가야 한다.(함수 본체가 밖에 있으면 함수 본체도 헤더에)
     → 메크로 함수보다 유리하다.


    - 전역 변수의 사용
     → 만약 함수의 변수가 iNum=0; 이고 전역변수의 이름도 iNum =  100; 이라면 함수내에서 iNum의 값을 읽을 때 0이 읽어진다.
     → 하지만 ::iNum이라고 호출하면 전역변수 100이 읽어진다. 즉, 스코프 연산자를 앞에 붙여서 같은 이름을 가진 전역 변수도 호출이 가능하다.
     → 예제
    #include<iostream.h>
    #include<stdlib.h>

    // 객체의 크기는 힙이나 스택에서 얼마만큼의 크기를 가지느냐다
    // 따라서 아래 emb 클래스의 크기는 8byte이다.
    // 포인터 변수 4byte, int형 4byte
    // 함수는 코드영역이므로 호출되었다 사라지므로 용량이 적용 안된다.

    class emb // emb 클래스를 부른다.
    {
      private :
        int *item;
        int iNum;  

      public :
        bool embInit();
        bool embInit(unsigned int uiNum);
        void embFree();
    };
    int iNum = 100;

    int main()
    {
      emb OBJ;
      //OBJ.iNum = 100; // 접근속성이 pivate 이므로 에러
      OBJ.embInit(); // 0으로 초기화 하는 함수
      OBJ.embInit(300); // 동적할당 및 전체 계수(1200byte)
      OBJ.embFree();
      
      cout << "main의 iNum = " << iNum << endl;
      cout << "class emb의 크기 = " << sizeof(emb) << endl;
      
      return 0;
    }
    // 스코프 연산자를 붙인다.
    bool emb::embInit()
    {  
      item = 0;
      iNum = 0;
      cout << "embInit" << endl;
      cout << "embInit() 내부 변수 iNum = " << iNum << endl;
      // 스코프(::)를 변수 이름앞에 붙이면 전역 변수 iNum을 출력한다.
      // 만약 class에 iNum이 있더라도 pivate 이므로 스코프로 출력할 수 없다.
      cout << "embInit()에서 전역 변수 iNum = " << ::iNum << endl;
      return true;
    }
    bool emb::embInit(unsigned int uiNum)
    {
      if(0 == uiNum)
      {
        return false;
      }
      item = (int *)malloc(sizeof(int)*uiNum);
      iNum = uiNum;
      cout << "embInit" << endl;

      return true;
    }
    void emb::embFree()
    {
      free(item);
      item = 0;
      iNum = 0;
      cout << "embFree" << endl;

      return ;
    }

     → 실행 결과


     → 마지막에 출력한 class emb의 크기를 살펴보면 8byte인 것을 확인할 수 있다.
     → 즉, 포인터 형의 크기 4바이트와 int형 크기 4바이트가 합쳐진 것으로, 함수는 사이즈에 포함되지 않음을 확인할 수 있다.


     → 함수의 인자와 내부변수의 이름이 같을 때 우선순위는 우선 함수 함수 안에 쓰여진 변수(내부 변수)가 높다.
     → 따라서 객체 자체가 자기 자신을 가리키는 포인터(자바는 참조)가 존재한다.
     → this-> or *this. 로 사용할 수 있다.
     ※ 참조 (자바는 기본적으로 참조형이다.)
     → 자바에서 기본형 int, char, short... 등이며 객체 참조 형은 변수(참조)가 객체를 가리키는 형태
     → 이것은 포인터와 같은 개념이며 자바는 기본형 빼고 전부 포인터 객체 참조와 같은 원리이다.

    - 알리아스(메모리를 차지 하지 않는다.)
    #include<stdio.h>

    int
     main()
    {
      int A = 100;
      int *P = &A;
      int &= A;
      
      printf("A = %X\n", A);  
      printf("P = %X\n", P);  
      printf("R = %X\n", R);  

      printf("A address = %X\n"&A);  
      printf("P address = %X\n"&P);  
      printf("R address = %X\n"&R);  
      
      R = 99;
      
      printf("A = %X\n", A);  
      printf("P = %X\n", P);  
      printf("R = %X\n", R);  

      return 0;
    }

     → 실행 결과


     → 변수 A와 R이 같은 주소와 값을 가지는 것을 확인할 수 있다.
     → 어셈블리 내에서 A와 R을 같이 취급(컴파일 단계)
     → 클래스를 만들 때 참조 변수가 필요하다.

     
    Posted by 동화다아아
    , |

    최근에 달린 댓글

    최근에 받은 트랙백

    글 보관함