Hyun2and
인프런 C++ 프로그래밍 입문 : 객체지향 본문
728x90
[인프런] C++ 프로그래밍 입문 을 보고 정리하는 글
객체지향의 시작
- C++ 은 C 기반으로 다른 기능들을 탑재하다보니 절차와 객체 사이 어딘가에 있다
Class
- 클래스를 정의하는 것 자체로는 메모리를 차지하지 않는다
- C++ 에서 class는 struct 와 은닉설정만 다르다
- 클래스 안에 함수를 정의해도 되긴하지만, 밖에 빼서 정의할 때에는 :: 로 클래스명을 정의한다
- 데이터와 동작을 함께 정의한다
- instantiate : 객체를 만든다
- 클래스 함수 내부에서 매개변수인지, 멤버변수인지 표시하기 위해 규칙이 있는 경우가 많다
- m_, m, _(언더바) 등
- 현 프로젝트에서는 클래스 멤버 변수는 크게 정의가 없고, 함수에 들어가는 변수는 In___ , 함수에서 포인터 값으로 전달해줄 변수는 out____ 으로 정의하고 있다
생성자와 소멸자
- 생성자 : 클래스가 생성될 때 호출.
- 여러개가 존재할 수 있다. 오버로딩해서 정의한다
- 소멸자 : 클래스가 소멸될 때 호출. 단 하나만 가진다
생성자
- 기본 생성자 : 인자가 없는 생성자
- 복사 생성자 : 자기 자신의 클래스 참조 타입을 인자로 받는다. 다른 값을 복사해서 만들겠다
Knight(const Knight& knight){ ... } // 기존의 클래스 인스턴스와 동일한 값을 가지는 인스턴스를 만들고 싶다 !
- 암시적 생성자 implicit : 생성자를 정의하지 않으면 컴파일러가 기본 생성자를 자동으로 만든다
- 사용할 수 있는 적절한 기본 생성자가 없습니다 → 인자에 맞는 생성자를 만들어줘야한다
- 특이한 경우
둘의 결과는 다르다 Knight k3 = k1; //복사 생성자를 호출함 Knight k4; // 기본 생성자를 호출함 k4 = k1
- 타입 변환 생성자
- 인자를 1개만 받아서, 해당 인자의 타입으로 맞춰주는 과정
- 암시적인 경우 컴파일러가 알아서 타입을 바꿔준다
- explicit 키워드 : 명시적인 용도로만 사용할 것이다
상속성
- 공통적인 속성을 최대한 재활용하기 위한 방법
- 부모의 내용을 상속받는다
- 메모리는 부모의 내용도 포함해서 메모리에 잡힌다
- 똑같은 이름의 함수로 부모의 요소를 재정의할 수 있다 (거의 쓰지는 않는다)
생성자, 소멸자
- 생성자는 각 클래스마다 호출되는 것
- 생성자와 소멸자는 상속이 되지 않는다. 각각 따로 존재
- 자식 클래스를 생성하면 자동으로 부모의 생성자가 호출된다
- 부모 생성자 먼저, 자식 소멸자 먼저
- 정확히는 자식 클래스의 생성자를 호출하려는 선처리 단계에서 부모 클래스의 생성자를 호출하는 것이다
- 자식 클래스의 소멸자 후처리 단계에서 부모 클래스의 소멸자를 호출하는 것이다
- 부모의 생성자도 지정해서 호출할 수 있다
Knight(int stemina) : Player(100){ }
- 보통 최상위 구조를 정의하고, 상속구조를 만든다
GameObject
~Creature
~ Player,
Monster
~ Projcetile
- Env
~ Item
~ Weapon
은닉성
- 안전성을 위해 감추는 것
- 캡슐화, Data Hiding, Encapsulation
- 왜 숨기나?
- 건들면 위험해지는 경우
- 다른 경우로 접근하길 원하는 경우
- 예시
class Car {
public : //일반적인 사용자가 사용하게 될 함수
void MoveHandle() { }
void PushPedal() { } //깊은 작업에서만 사용하게 될 함수
void DisassembleCar() { }
void RunEngine() { }
}
int main()
{
Car car;
return 0;
}
접근지정자
- C++ 에서는 class에 한 번만 작성해주면 된다class Car{ public : ~~ }
- public : 누구에게나 공개됨
- protected : 나, 나의 자식들에게만 허용한다
- private : 클래스 내부에서만 사용할 것
캡슐화
- 연관된 데이터와 함수를 논리적으로 묶어놓은 것
- get, set 함수를 만들어줘야 한다
- 외부에서 모르는 사람이 쓰더라도 사양과 기능에 부합하도록 노출시켜야 한다
상속접근지정자
- 다음 세대에게 부모의 자산을 어떻게 물려줄 것인지
- 반드시 자식에게 부모의 모든 것을 동일하게 물려줄 필요는 없다
- public 상속을 보통 많이쓴다
- 상속 종류
- public : 부모의 상속을 그대로 열어주겠다
- protected : 부모의 public 요소들을 protected로.
- private : public , protected 까지도 전부 private로 만든다
다형성 (Ploymorphism)
- 겉은 비슷하지만 내부가 다르게 작동한다
- 오버로딩 : 같은 이름의 함수를 재사용한다
- 오버라이딩 : 부모 클래스의 함수를 자식 클래스에서 재정의한다
오버로딩
- 같은 이름을 가지지만 매개변수가 다른 함수를 정의한다
void Move() { } void Move(int a) { }
오버라이딩
- 부모의 요소를 자식 클래스에서 재정의한다
class Player(){ void Move(){ } }
class Knight : Player { void Move(){ } }
- 애매한 상황들이 생긴다
void MovePlayer(Player* player){ }
void MoveKnight(Knight* knight){ }
int main(){
Player p;
MovePlayer(&p);
MoveKnight(&p); // Err. Player라고해서 Knight라고 할 수 있나?
}
바인딩
- 정적 바인딩 : 어떤 함수를 호출할지 컴파일 시점에 결정한다
- 동적 바인딩 : 어떤 함수를 호출할지 실행 시점에 결정한다
- 일반 함수들은 정적 바인딩을 쓰기 때문에, 동적 바인딩을 하기 위해서는 가상함수를 사용해야 함
class Player(){
void Move(){ }
virtual void MoveVirtual() { }
}
class Knight : Player {
void Move() { }
virtual void MoveVirtual() { }
}
int main() {
Player* p = new Knight(); p->Move(); // 부모의 함수가 호출된다
p->MoveVirtual(); //자식의 함수가 호출된다
}
초기화 리스트
- 멤버 변수들을 초기화하는 부분
- 왜 초기화를 해야할까?
- 버그 예방에 중요함
- 포인터 등 주소값이 들어가 있을 경우
class Knight { }
- stack 메모리 특성상 이전의 메모리를 재사용할 수 없다
- 클래스 정의 시 멤버들의 값이 쓰레기값으로 들어가 있다
- 초기화 방법
- 생성자 내
- 초기화 리스트
- C++ 11 문법
int _hp = 200; // 기존의 C++에서는 불가능했다
초기화 리스트
- 상속 관계에서 원하는 부모 생성자를 호출하는 경우
- 일반변수는 생성자에서 초기화 하는 것과 차이 없음
- 멤버 타입이 클래스인 경우 사용됨
- 관계가 상속(is a) 관계인지, 포함(has a) 관계인지class Knight : public Player { public: Knight() : Player(1), _hp(100) //선처리 영역 에서 Inventory의 기본 생성자가 호출된다 { } public: Inventory _inventory; }
- 포함관계인 클래스 Inventory 의 생명주기는 Knight를 따른다. Knight의 선처리 과정에서 함께 생성된다
- 직접 다른 생성자를 쓰고자 할 때 생성자가 2번 호출되게 된다
- 결론 : 생성자 리스트에 적어주면 중복생성을 막을 수 있다!
class Knight { public : Knight() : Player(1), _hp(100), _inventory(20) { } }
class Knight {
public :
Knight()
{
_inventory = Inventory(20); // 기본 생성자가 아닌 다른 생성자로 호출하면서 기존의 생성자를 덮어씌우게 된다
}
}
+ 무조건 생성자 리스트에만 넣게 되는 경우
- 참조 타입이나, const 는 생성자 리스트에 넣었어야 했다
연산자 오버로딩
- 연산자를 커스터마이징 한다
- 함수 오버로딩과의 차이
- 연산자는 피연산자의 개수, 타입이 고정되어 있다
- operator 키워드를 통해 작성한다
- a op b 인 경우, a 를 기준으로 실행된다
Position operator+(const Position& arg) { }
- a가 클래스가 아니면 사용할 수 없다
- 1 + pospos + 1 로 써야함
728x90
'공부엔 끝이없다 > 인프런 C++' 카테고리의 다른 글
인프런 C++ 프로그래밍 입문 : Modern C++ (0) | 2023.02.20 |
---|
Comments