경일게임아카데미 멀티 디바이스 메타버스 플랫폼 개발자 양성과정 20220530 2022/04/04~2022/12/13

Jinho Lee·2022년 5월 30일
0

경일 메타버스 20220530 9주차 1일 수업내용. 커리큘럼, 공부법, OOP with C++ 객체 지향 프로그래밍, C++ 프로그래밍 문법

정리

객체지향 프로그래밍 개념

  • 절차지향 프로그래밍이 불편했기 때문에 등장했다.
    • 프로그램 유지보수가 힘들기 때문
  • 4가지 개념
    • 캡슐화(Encapsulation) : 데이터와 함수를 같이 작성하는 것
    • 상속(Inheritance) : 코드를 물려 받는 것
    • 추상화(Abstraction) : 사용하기 쉽게 인터페이스를 정의하는 것
    • 다형성(Polymorphism) : 같은 인터페이스를 사용하되 서로 다른 동작을 하게 하는 것
  • 객체에서 데이터를 필드(Field), 함수를 메소드(Method)라고 한다.

C++ 프로그래밍

  • 레퍼런스(Reference) : 간접 참조를 위한 타입
    • 포인터의 불편함
      (1) Null 체크를 해야 한다.
      (2) 역참조 연산자를 써야 한다.
  • 클래스 : 객체의 청사진
    • 클래스 타입 : struct, class, union
    • C언어에서 구조체 만드는 것과 문법은 비슷함.
    • 클래스 내부에서 선언된 식별자는 클래스 범위(Class Scope)를 가진다.
    • 멤버에는 변수랑 함수를 가질 수 있다.
    • 클래스를 바탕으로 메모리에 표현한 것을 인스턴스(Instance)라고 한다.
  • 접근 지정자
    • public : 클래스 외부에서 접근 가능
    • protected : 몰?루
    • private : 클래스 내부에서 접근 가능
  • 생성자 : 초기화를 담당하는 특수한 메소드
    • 기본 생성자는 아무런 생성자도 정의하지 않았을 때 컴파일러가 자동으로 합성한다.
    • 복사 생성자
      • 첫 번째 매개변수로 동일한 타입의 레퍼런스를 가지는 생성자
      • 복사 생성자도 정의하지 않으면 기본으로 합성된다.
  • 소멸자 : 자원 정리를 담당하는 특수한 메소드
    • 소멸자를 정의하지 않았을 때 컴파일러가 자동으로 합성한다.

커리큘럼

  1. OOP with cpp (1 week)
  2. DS with STL and Algorithm (3 weeks)
  3. C# programming (1 week)
  4. Unity (3 weeks)
  5. VR / AR (1 week)
  6. 프로젝트 예상
  7. NFT (8 weeks 예상)
  8. 기업 협약 프로젝트

앞으로의 수업 방향

  • 실습과 병행하여 수업 진행이 되며, 이론 4시간 / 실습 4시간 딱 나누기 보단 짧은 단위로 끊어서 진행
  • 기본 / 심화로 나눔. 심화는 추가로 제시만 할 것.
  • 수업 중에는 낙서장 이용 X. 질문은 #질의응답 채널에 남길 것.
  • 추가 공부 자료는 #자료공유에 올릴 예정.
  • 과제는 필요하다면 낼 예정.
  • 성취도 파악을 위해 수시로 룰렛 돌려서 질문.
  • 마지막에 한 번 정리 → 수업 오버될 수 있음.

공부법

정리

  • 정리는 구조적으로 할 것.
  • 책의 내용은 Outdated한 자료이므로, 반드시 정식 문서를 연결할 것.
  • 연결되는 내용을 묶어서 정리하고 개념을 모아서 쓸 것.
  • 마지막에는 블로그에 정리, 누군가에게 가르친다는 생각으로.
  • 배운 내용은 테스트 해보고 결과를 볼 것. (고생한 만큼 머리에 남는다.)

언어

  • 프로그래밍 언어를 공부하는 방법은, 언어는 코어(문법)와 라이브러리로 나뉘기에, 코어 : 문법(타입 / 구문 (제어문 등) / 함수)을 익히는 것으로 언어를 익힐 수 있다.
  • 언어가 여러 가지 있는 이유 : 언어 작성자마다의 철학이 있기 때문
  • 프로그래밍 패러다임 : 언어의 사고방식
  • 언어를 얼마나 알아야 하는가 : 네이티브 언어 하나, 매니지드 언어 하나 쯤은 알고 있어야 한다. (네이티브 : C++, Rust / 매니지드 : C#)

OOP

Object-Oriented Programming(OOP), 객체 지향 프로그래밍

  • 프로그램을 수많은 객체(object)라는 기본 단위로 나누고 이들의 상호작용으로 서술하는 프로그래밍 방식
    • 절차 지향 프로그래밍 (Procedural Programming) : 함수를 중심으로 프로그램을 구성하는 방법
    • 객체 지향 프로그래밍 (Object-Oriented Programming) : 객체를 중심으로 프로그램을 구성하는 방법

절차 지향 프로그래밍의 한계

  1. 데이터와 데이터를 다루는 함수분리되어 있다.

    • 매번 어떤 매개변수를 받을지 설계해야 하고 그 주소 값을 받아야 하는 문제점이 있었다. 함수 내부에서도 포인터로 데이터를 다루는 불편함이 있었다.
  2. 함수의 이름을 항상 다르게 작성해야 한다.

    • C언어에서 함수의 이름은 전역 이름 공간을 사용하기에, 매번 다른 이름을 다르게 지어줘야 했다.
  3. 프로그램을 확장하기 불편하다.

    • 항상 함수를 명확히 호출해야 하기에, 프로그램에 수정 사항이 생기면 그에 따른 변경 사항이 많아졌다.

    • 이를 줄이기 위해 함수 포인터를 사용하거나 특정 타입이 무엇인지 가려내기 위해 추가적인 데이터를 할당했다. 하지만 이 또한 유지 보수에 비효율적이다.

OOP의 주요 개념 4가지

1. 캡슐화(Encapsulation)

  • 캡슐화데이터와 데이터를 다루는 함수같이 작성하는 것이다.

    2022. 05. 30 캡슐화 예시 코드

  • 객체 지향 언어에서는 어떤 객체를 생성하기 위해 생성자(Constructor)라 하는 특수한 함수를 이용한다.

    • 다른 함수처럼 어떤 매개변수를 받아 객체를 초기화할지, 어떻게 초기화할지를 결정할 수 있다.
  • 인자를 통해서 받았던 포인터 변수는 this 포인터라는 특수한 포인터로 대체된다.

  • 어떤 객체를 사용함에 있어 객체를 올바르게 사용할 수 있도록 접근 지정자(Access Specifier)라는 게 있어 외부에 공개할 것과 그렇지 않은 것을 구분 지을 수 있다.

  • 객체지향 프로그래밍에서 데이터 부분필드(Field), 함수메소드(Method)라고 한다.

2. 상속(Inheritance)

  • 상속은 코드를 물려받는 것을 의미. 즉, 코드를 재사용할 수 있다.
    상속을 이용하면 타입을 더 작은 단위로 모듈화 할 수 있다.

  • 모듈화(Modularization) : 기능적으로 부분을 모듈로 분리하여 유지보수 효율코드 재사용성을 높이는 기법.

    2022. 05. 30 상속 예시 코드

3. 추상화(Abstraction)

  • C++의 창시자 비야네 스트롭스트룹 교수님 : 추상화란,

    • 구현 세부 정보숨기는 일반적인 인터페이스를 정의하는 행위’

    • 인터페이스 : 서로 다른 부분이 만나고 소통하거나 서로에게 영향을 미치는 영역

  • 추상화를 잘 하면 잘 할 수록 데이터를 다루기 쉬워지게 되며, 이는 프로그램을 더 빠르고 편리하고 안전하게 작성할 수 있다는 것을 의미한다.

  • 구현 세부 사항에 변화가 생기게 되더라도 사용하는 입장에서는 달라지는 것이 없으므로 확장성 또한 가지게 된다.

4. 다형성(Polymorphism)

  • 다형성은 여러가지 형태를 가지는 것을 의미한다.

  • 다형성은 객체 지향 프로그래밍의 핵심으로 잘 다루는 것이 중요하다.

  • 코드를 변경하지 않아도 내용을 바꿀 수 있다.

    • 다형성을 이용하려면 가상 함수(Virtual Function)가 필요하다.

    • 가상 함수는 인터페이스를 유지한 채로 구현 세부 사항을 바꿀 수 있다.
      이를 오버라이딩(Overriding)이라 한다.

    • 가상 함수를 이용하려면 상위 타입의 포인터를 이용해야 한다.

    • 가상 함수 : 부모 클래스에서 상속 받을 클래스 내부에서 재정의할 것으로 기대하고 정의한 함수.

      • 일반 함수와 달리 다형성을 이용 가능하고, 오버라이딩이 가능하다.

    2022. 05. 30 다형성 예시 코드

  • 객체 지향 프로그래밍을 사용함으로써 분기문을 내부에서 작동하도록 하는 것 (분기문을 코드로 지정하지 않아도 되는 것) 이 가능하다.
    예시) NewFrontier 프로젝트의 Scene 전환 switch문

    • 즉, 확장성이 떨어지는 절차 지향 프로그래밍과 달리 확장성이 뛰어나다.

C++ 프로그래밍 문법

레퍼런스(Reference)

  • 간접 참조

    • 객체마다 범위가 있기에, 그 범위 밖에서 접근하기 위해 사용.
    • 또한, 참조할 객체의 크기가 큰 경우, 전부 복사해 오기 보단 간접 참조로 8바이트의 포인터를 사용하는 편이 기능적으로 좋음.
    • 다만, 포인터는 2가지 불편함이 있다.
      1. 포인터는 널(Null) 값이 포함될 수 있다.
      2. 간접 참조로 데이터를 다루기 위해선 역참조 연산자를 계속 사용해야 한다.
    • 그 해결을 위해 C++에서는 레퍼런스가 등장했다.
  • 레퍼런스 (Reference)

    • https://en.cppreference.com/w/cpp/language/reference

    • 레퍼런스는 간접 참조를 위해 만들어진 타입.

      • 문법:
      • int& ref;
      • sizeof(ref) = 4; // 포인터는 8바이트, 레퍼런스는 4바이트
      • 초기화 필요
      • 주의 : 레퍼런스는 변수의 별칭이 아니다.
      1. 레퍼런스는 널(NULL) 값이 들어올 수 없다.
      2. 역참조 연산자 *를 사용하지 않아도 된다.
      3. 레퍼런스에 주소 연산불가능하다.
      4. 레퍼런스는 꼭 초기화를 해줘야 한다.
      5. 레퍼런스의 레퍼런스, 레퍼런스의 배열, 레퍼런스의 포인터는 존재할 수 없다.
      6. 상수 (리터럴) 값, 함수의 리턴 값은 상수 레퍼런스 const & 로 받을 수 있다.

    2022. 05. 30 레퍼런스 예시 코드

클래스(Class)

// class 자리에는 struct, class, union 키워드를 작성할 수 있다.
// struct와 class는 기본 동작만 다르다.
// union은 특수한 클래스 타입으로 분류된다.
class A
{
    // 클래스 내부에서 선언된 식별자는 클래스 범위(Class Scope)를 가진다.
    int     _data;
    double _data2;

    // 멤버로는 함수도 가질 수 있다.
    void foo();
};

// 클래스 타입의 변수는 기본 타입과 똑같이 정의할 수 있다.
// 이전처럼 struct와 같은 키워드를 작성하지 않아도 된다.
A a; // a를 A에 대한 인스턴스(Instance)라고 한다.

// 메모리에 표현되는 것은 C의 구조체의 그것과 같다.
// [ _data(4) ][ padding(4) ][ _data2(8) ]
  • C++에서 struct와 class는 똑같은 class타입이다.

    • 즉, struct를 써도 똑같은 캡슐화가 가능하다.
  • 필드와 메소드로 구성된다.

  • 인스턴스 (Instance) : 영어 뜻 : 예시. 객체가 더 포괄적인 개념으로, 메모리의 특정 부분을 객체라고 하고, 인스턴스는 그 중 클래스를 바탕으로 만들어진 객체 (메모리)이다.

  • 외부에 공개할 것과 공개하지 않을 것을 구분 짓기 위해 접근 지정자(Access Specifier)를 제공한다.

  • 접근 지정자 공식 문서: https://en.cppreference.com/w/cpp/language/access

  • 접근 지정자에는 public, protected, private이 있다.

    • protected는 후술할 상속 파트에서

    • private은 클래스 외부에서 접근할 수 없다. <- 출력도 불가능하다는 의미.

    • public은 클래스 외부에서 접근할 수 있다.

// class의 기본 접근 지정자는 private이다.
class A
{
    // 이 아래는 private 영역이다.
    // private은 클래스 외부에서 접근할 수 없다.
    int _privateData;
    
    // 이 아래는 public 영역이다.
    // public은 클래스 외부에서 접근할 수 있다.
public:
	int PublicData;
};

A a;

a._privateData; // 컴파일 오류; 접근 불가능
a.PublicData; // 접근 가능

기본 메소드(Default Method)

  • 클래스 타입이 기본적으로 갖고 있는 메소드.

1. 기본 생성자(Default Constructor)

  • https://en.cppreference.com/w/cpp/language/default_constructor

  • 생성자인스턴스의 초기화를 담당하는 특수한 메소드

  • 생성자는 기본적으로 반환타입을 갖지 않고, 타입의 이름과 동일하게 식별자를 사용한다.

  • 암시적 방법 / 명시적 방법으로 호출할 수 있다.

    • 암시적
      A a(data); // 암시적 방법 (implicit)
    • 명시적
      A b = A(data); // 명시적 방법 (explicit)
  • 매개변수가 없는 생성자를 기본 생성자라고 한다.

       class A
       {
       public:
           // 생성자의 문법은 기본적으로 반환타입을 갖지 않고,
           // 타입의 이름과 동일하게 식별자를 사용한다.
           // 매개변수가 없는 생성자를 기본 생성자라고 한다.
           A()
           : _data(0); // 이 부분을 멤버 초기화 목록(Member Initializer List)이라고 한다.
           {
               _data = 10; // 여기는 초기화가 아니라 '할당'이다.
               // 초기화 외에 인스턴스를 만들면서 해야할 일들을 적는다.
           }
            
            // 생성자는 필요한만큼 오버로딩이 가능하다.
       	A(int data) : _data(data) { }
    	  
       private:
           int _data;
       };
            
       // 둘은 다르다.
       A a;	// 기본 생성자가 호출된다. a._data는 0이다.
       A b();	// 반환값이 클래스 A인, 매개변수가 없는 함수 b의 선언
       A c(10); // A(int data) 생성자가 호출된다. c._data는 10이다.
  • 기본 생성자는 클래스 안에 아무런 생성자도 적어주지 않을 시 자동으로 합성된다.

class A
{
  // 생성자를 정의해주지 않았지만 자동으로 컴파일러에 의해 만들어진다.
  // 이 때 자동으로 만들어지는 생성자는 아래와 같다.
  // A() { }
  int _data;
};

// 멤버 중에 클래스 타입이 있는 경우 기본 생성자를 호출하게 된다.
A a;

class B
{
public:
  // 생성자를 하나 만들어주었으므로
  // 기본 생성자는 더 이상 만들어지지 않는다.
  B(int data)
   : _data(data)
  { }

private:
  int _data;
};

B b; // 컴파일 오류; 기본 생성자가 없으므로 만들 수 없음.

2. 복사 생성자(Copy Constructor)

  • https://en.cppreference.com/w/cpp/language/copy_constructor

  • 생성자 중 동일 타입의 레퍼런스를 첫 번째 매개변수, 인자로 받는 생성자

  • 복사 생성자의 용도는 다른 인스턴스의 데이터를 완전히 복사하는 것이다.

  • 복사 생성자도 기본 생성자와 마찬가지로 아무런 복사 생성자가 정의되어 있지 않을 시 자동으로 합성된다. 이를 기본 복사 생성자(Default Copy Constructor)라고 한다.

    class A
    {
    public:
        A(int data)
        : _data(data) { }
        // 복사 생성자의 용도는 말 그대로 다른 인스턴스의
        // 데이터를 완전히 복사하는 것이다.
        A(const A& other)
         : _data(other._data) { }
         
    private:
        int _data;
    };
          
    A a(10);
    A a2(a); // 복사 생성자 호출. a2._data는 a._data와 동일하다.
    A a3 = a; // 이 경우에도 복사 생성자가 호출된다.
      
  • 특히 멤버에 포인터가 있는 경우 복사 생성자를 만들 때 주의해야 한다.

    • Shallow Copy
      • 멤버에 대한 단순 대입
      • 포인터 또한 그대로 대입하기에, 같은 주소를 가리키게 되는 문제가 발생
    • Deep Copy
      • 포인터를 대입할 때, 따로 메모리를 할당하여 내용만 복사
      • 기본 생성과는 다른 작업을 수행하기에 기본 복사 생성자는 불가
    • 2022. 06. 02 추가) 복사 생성자 Shallow Copy & Deep Copy 예시 코드

3. 기본 소멸자(Default Destructor)

  • https://en.cppreference.com/w/cpp/language/destructor

  • 객체의 수명이 다할 때 자동으로 호출되는 특수한 메소드.

  • 반환 타입이 없으며, 식별자는 타입 이름 앞에 ~를 붙이고 매개변수가 없다.

  • 자원을 정리하기 위해 사용. 메모리를 반환.

  class A
  {
  public:
      A() : _p(malloc(sizeof(int) * 3)) { }
           
      // 소멸자도 생성자와 마찬가지로 반환 타입이 없으며
      // 식별자는 타입 이름 앞에 ~를 붙이고
      // 아무런 매개변수도 적지 않는다.
      // 보통 이와 같이 자원을 정리할 때 사용한다.
      ~A() { free(_p); _p = nullptr; }
  private:
      int*    _p;
  };
         
  {
      A a;
  } // 이 부분에서 a.~A(); 가 호출된다.
  • 소멸자도 정의되지 않으면 기본 소멸자가 자동으로 컴파일러에 의해 합성된다.
   class A
   {
   private:
      int _data;
   };
         
   {
      A a; // a의 기본 생성자가 호출된다.
   } // a의 기본 소멸자가 호출된다.

RAII 테크닉

  • Resource Acquisition Is Initialization. 객체의 생성과 자원의 반환지어 주어야 한다. C++ 프로그래머라면 반드시 알아야 할 테크닉.

참고

0개의 댓글