경일 메타버스 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 : 클래스 내부에서 접근 가능
- 생성자 : 초기화를 담당하는 특수한 메소드
- 기본 생성자는 아무런 생성자도 정의하지 않았을 때 컴파일러가 자동으로 합성한다.
- 복사 생성자
- 첫 번째 매개변수로 동일한 타입의 레퍼런스를 가지는 생성자
- 복사 생성자도 정의하지 않으면 기본으로 합성된다.
- 소멸자 : 자원 정리를 담당하는 특수한 메소드
- 소멸자를 정의하지 않았을 때 컴파일러가 자동으로 합성한다.
- OOP with cpp (1 week)
- DS with STL and Algorithm (3 weeks)
- C# programming (1 week)
- Unity (3 weeks)
- VR / AR (1 week)
- 프로젝트 예상
- NFT (8 weeks 예상)
- 기업 협약 프로젝트
- 실습과 병행하여 수업 진행이 되며, 이론 4시간 / 실습 4시간 딱 나누기 보단 짧은 단위로 끊어서 진행
- 기본 / 심화로 나눔. 심화는 추가로 제시만 할 것.
- 수업 중에는 낙서장 이용 X. 질문은 #질의응답 채널에 남길 것.
- 추가 공부 자료는 #자료공유에 올릴 예정.
- 과제는 필요하다면 낼 예정.
- 성취도 파악을 위해 수시로 룰렛 돌려서 질문.
- 마지막에 한 번 정리 → 수업 오버될 수 있음.
Object-Oriented Programming(OOP), 객체 지향 프로그래밍
- 절차 지향 프로그래밍 (Procedural Programming) : 함수를 중심으로 프로그램을 구성하는 방법
- 객체 지향 프로그래밍 (Object-Oriented Programming) : 객체를 중심으로 프로그램을 구성하는 방법
데이터와 데이터를 다루는 함수가 분리되어 있다.
함수의 이름을 항상 다르게 작성해야 한다.
프로그램을 확장하기 불편하다.
항상 함수를 명확히 호출해야 하기에, 프로그램에 수정 사항이 생기면 그에 따른 변경 사항이 많아졌다.
이를 줄이기 위해 함수 포인터를 사용하거나 특정 타입이 무엇인지 가려내기 위해 추가적인 데이터를 할당했다. 하지만 이 또한 유지 보수에 비효율적이다.
캡슐화는 데이터와 데이터를 다루는 함수를 같이 작성하는 것이다.
객체 지향 언어에서는 어떤 객체를 생성하기 위해 생성자(Constructor)라 하는 특수한 함수를 이용한다.
인자를 통해서 받았던 포인터 변수는 this 포인터라는 특수한 포인터로 대체된다.
어떤 객체를 사용함에 있어 객체를 올바르게 사용할 수 있도록 접근 지정자(Access Specifier)라는 게 있어 외부에 공개할 것과 그렇지 않은 것을 구분 지을 수 있다.
객체지향 프로그래밍에서 데이터 부분을 필드(Field), 함수를 메소드(Method)라고 한다.
상속은 코드를 물려받는 것을 의미. 즉, 코드를 재사용할 수 있다.
상속을 이용하면 타입을 더 작은 단위로 모듈화 할 수 있다.
모듈화(Modularization) : 기능적으로 부분을 모듈로 분리하여 유지보수 효율과 코드 재사용성을 높이는 기법.
C++의 창시자 비야네 스트롭스트룹 교수님 : 추상화란,
‘구현 세부 정보를 숨기는 일반적인 인터페이스를 정의하는 행위’
인터페이스 : 서로 다른 부분이 만나고 소통하거나 서로에게 영향을 미치는 영역
추상화를 잘 하면 잘 할 수록 데이터를 다루기 쉬워지게 되며, 이는 프로그램을 더 빠르고 편리하고 안전하게 작성할 수 있다는 것을 의미한다.
구현 세부 사항에 변화가 생기게 되더라도 사용하는 입장에서는 달라지는 것이 없으므로 확장성 또한 가지게 된다.
다형성은 여러가지 형태를 가지는 것을 의미한다.
다형성은 객체 지향 프로그래밍의 핵심으로 잘 다루는 것이 중요하다.
코드를 변경하지 않아도 내용을 바꿀 수 있다.
다형성을 이용하려면 가상 함수(Virtual Function)가 필요하다.
가상 함수는 인터페이스를 유지한 채로 구현 세부 사항을 바꿀 수 있다.
이를 오버라이딩(Overriding)이라 한다.
가상 함수를 이용하려면 상위 타입의 포인터를 이용해야 한다.
가상 함수 : 부모 클래스에서 상속 받을 클래스 내부에서 재정의할 것으로 기대하고 정의한 함수.
객체 지향 프로그래밍을 사용함으로써 분기문을 내부에서 작동하도록 하는 것 (분기문을 코드로 지정하지 않아도 되는 것) 이 가능하다.
예시) NewFrontier 프로젝트의 Scene 전환 switch문
간접 참조
레퍼런스 (Reference)
레퍼런스는 간접 참조를 위해 만들어진 타입.
// 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타입이다.
필드와 메소드로 구성된다.
인스턴스 (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; // 접근 가능
https://en.cppreference.com/w/cpp/language/default_constructor
생성자는 인스턴스의 초기화를 담당하는 특수한 메소드
생성자는 기본적으로 반환타입을 갖지 않고, 타입의 이름과 동일하게 식별자를 사용한다.
암시적 방법 / 명시적 방법으로 호출할 수 있다.
매개변수가 없는 생성자를 기본 생성자라고 한다.
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; // 컴파일 오류; 기본 생성자가 없으므로 만들 수 없음.
생성자 중 동일 타입의 레퍼런스를 첫 번째 매개변수, 인자로 받는 생성자
복사 생성자의 용도는 다른 인스턴스의 데이터를 완전히 복사하는 것이다.
복사 생성자도 기본 생성자와 마찬가지로 아무런 복사 생성자가 정의되어 있지 않을 시 자동으로 합성된다. 이를 기본 복사 생성자(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; // 이 경우에도 복사 생성자가 호출된다.
특히 멤버에 포인터가 있는 경우 복사 생성자를 만들 때 주의해야 한다.
객체의 수명이 다할 때 자동으로 호출되는 특수한 메소드.
반환 타입이 없으며, 식별자는 타입 이름 앞에 ~를 붙이고 매개변수가 없다.
자원을 정리하기 위해 사용. 메모리를 반환.
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의 기본 소멸자가 호출된다.