로보테크AI

융합_로보테크 AI 자율주행 로봇 개발자 과정-26/02/13

steezer 2026. 2. 13. 18:30

클래스

데이터와 함수를 포함하는 논리단위

클래스: 객체가 포함하는 데이터와 함수를 정의하는 문법적인 요소

객체: 특정 클래스를 사용할 수 있도록 만든 변수

 

클래스 정의 문법

클래스 선언부:

클래스의 이름, 부모 클래스, 멤버 변수·함수의 선언을 포함하는 구조 정의 영역이다.
멤버 함수별 정의부:

클래스 밖에서 클래스이름::함수이름 형태로 실제 동작을 구현하는 부분이다.
클래스 선언 키워드:

사용자 정의 타입을 만들기 위해 사용하는 class 키워드이다.
클래스 이름:

생성할 객체 타입의 이름으로, 자료형처럼 사용된다.
부모 클래스(선택):

상속을 위해 : 접근지정자 부모클래스명 형태로 지정하는 상위 클래스이다.
접근 지정자:

public, private, protected로 멤버의 접근 범위를 제어하는 키워드이다.
생성자와 소멸자(선택):

객체 생성 시 초기화를 담당하는 함수와, 객체 소멸 시 정리를 담당하는 함수이다.
멤버 함수 선언과 정의:

선언은 함수의 형태만 명시하고, 정의는 실제 실행 코드를 작성하는 것이다.
멤버 변수 선언:

클래스 내부에 객체가 가질 데이터(속성)를 정의하는 부분이다.
멤버 함수 네임스페이스: 

클래스 외부에서 정의할 때 클래스이름:: 범위 지정 연산자로 소속을 명시하는 문법이다.

 

클래스 객체 선언

클래스를 데이터 형식으로 삼고 객체를 선언

new 키워드를 사용하여 동적메모리를 할당하는 방법

 

// 클래스 정의
class engine{...생략...};

//클래스를 데이터 형식처럼 사용하는 방법
engine my_engine;

//클래스 형식으로 동적 메모리 할당과 해제 방법
engine *my_engine_pointer = new engine();
delete my_engine_pointer;

 

객체의 클래스의 멤버에 접근

my_engine.current_fuel; //멤버 변수에 접근
my_engine.increasing_piston_speed(); //멤버 함수 호출

 

 

추상화

공통된 특징은 추출하고 불필요한 부분은 제거하여 코드를 간결하고 이해하기 쉽게 만드는 작업

공통 특징 추출

불필요 요소 제거

 

캡슐화

변수와 함수를 클래스로 감싸서 외부에서 개별적으로 접근할 수 없도록 하나로 묶어 관리하는 것

ㄴ접근 지정자

ㄴㄴprivate: 클래스 내 멤버 함수에서만 접근 가능

ㄴㄴpublic: 다른 클래스 어디서든 접근 가능

ㄴㄴprotected: 클래스 내 멤버 함수나 상속 관계의 클래스에서 접근 가능

 

#include <iostream> 

using namespace std;

class bank {
private:
  int safe;    // 금고 

public:
  bank();      // 기본 생성자  
  void use_counter(int _in, int _out);   // 입출금 창구 함수 
};

// 클래스명과 같은 이름의 함수는 '생성자'라 함
// 생성자의 역할은 멤버 변수 초기화
bank::bank() {
  safe = 1000;    // 은행 금고 초기 금액 설정 
  cout << "최초 금고 : " << safe << endl;
  cout << endl;
}

void bank::use_counter(int _in, int _out) {
  safe += _in;     // 입금 
  safe -= _out;    // 출금 

  cout << "입금 : " << _in << endl;
  cout << "출금 : " << _out << endl;
  cout << "금고 : " << safe << endl;
  cout << endl;
}

int main() {
  // 생성자는 변수 선언할 때 자동 호출됨
  bank my_bank; // my_bank 인스턴스 생성

  my_bank.use_counter(0, 20);     // 출금 20 
  my_bank.use_counter(50, 0);     // 입금 50 
  my_bank.use_counter(100, 50);   // 입금 100, 출금 50 

  return 0;
}

 

최초 금고 : 1000

입금 : 0
출금 : 20
금고 : 980

입금 : 50
출금 : 0
금고 : 1030

입금 : 100
출금 : 50
금고 : 1080

 

객체: 논리적 개념으로 클래스로 구현하고자 하는 구현 대상, 또는 인스턴스를 달리 부를 때 사용

클래스: 객체를 구현하기 위한 설계도

인스턴스: 클래스 정의에 따라 메모리에 실체화된 객체의 형태

 

class Coffee {};

Coffee americano; //인스턴스화

 

Coffee라는 '클래스'를 이용해서 americano라고 하는 '객체'를 생성

americano는 Coffe의 '인스턴스'

 

추상화와 캡슐화를 이용한 클래스 설계

#include <iostream>
using namespace std;

class character {
public:
  character() : hp(100), power(100) {};

protected:
  int hp;
  int power;
};

//character 클래스를 상속 받은 player 클래스
class player : public character {
public:
  player() {};
};

//기본 Monster 클래스
class monster {
public:
  monster() {};
  void get_damage(int _damage) {};
  void attack(player target_player) {};
  void attack_special(player target_player);
};

void monster::attack_special(player target_player) {
  cout << "기본 공격 : 데미지 - 10 hp" << endl;
}

//몬스터 A는 기본 Monster 클래스로부터 상속
class monster_a : public monster, character {
public:
  //상속받은 함수 오버라이딩 
  void attack_special(player target_player);
};

void monster_a::attack_special(player target_player) {
  cout << "인텡글 공격 : 데미지 - 15 hp" << endl;
}

//몬스터 B는 기본 Monster 클래스로부터 상속
class monster_b : public monster, character {
public:
  //상속받은 함수 오버라이딩
  void attack_special(player target_player);
};

void monster_b::attack_special(player target_player) {
  cout << "가상 공격 : 데미지 - 0 hp" << endl;
}

//몬스터 C는 기본 Monster 클래스로부터 상속
class monster_c : public monster, character {
public:
  //상속받은 함수 오버라이딩
  void attack_special(player target_player);
};

void monster_c::attack_special(player target_player) {
  cout << "강력 뇌전 공격 : 데미지 - 100 hp" << endl;
}

int main() {
  player player_1;

  monster_a forest_monster;
  monster_b tutorial_monster;
  monster_c boss_monster;

  cout << "몬스터 총 공격" << endl;
  tutorial_monster.attack_special(player_1);
  forest_monster.attack_special(player_1);
  boss_monster.attack_special(player_1);

  return 0;
}

 

몬스터 총 공격
가상 공격 : 데미지 - 0 hp
인텡글 공격 : 데미지 - 15 hp
강력 뇌전 공격 : 데미지 - 100 hp

 

어떤 대상을 소프트웨어로 구현하려 할 때

1.추상화: 공통적인 특성을 추리고 그 중 불필요한 것 제외

ㄴ구현해야 할 변수와 함수 종류가 남게 됨

2.구체화: 변수와 함수의 명세(이름, 자료형, 매개변수나 반환형 등)를 정한다

3.전체적인 흐름을 그리고 실제 코드로 옮기는 작업

 

 

상속성

클래스를 만들 때 다른 클래스의 멤버를 물려받는 것

다양한 특성으로 추상화하고 캡슐화한 클래스를 확장하고 변형하는 방법

이때 상속받은 클래스를 자식, 파생, 하위 클래스라 함

반대로 상속해 주는 클래스는 부모, 기본, 슈퍼 클래스라고 함

 

확장: 물려받은 것 말고도 다른 걸 더 추가

변형: 물려받은 것을 그대로 쓰는게 아니라 재정의해서 사용

 

리스코프 치환 원칙: 자식 클래스는 부모 클래스를 완전히 대체할 수 있다는 원칙

 

파일 읽기 인스턴스 생성

#include <iostream>
#include <algorithm>
#include <string>

using namespace std;

class file_reader_original {
public:
  static int read_header();
  static file_reader_original* get_reader_instance();
  virtual void read_contents() = 0;
};

int file_reader_original::read_header() {
  // v1.0 이라고 가정
  return 1;

  // v2.0 이라고 가정
  //return 2;
}

class file_reader_v0100 : public file_reader_original {
private:
  virtual void read_contents() override;
};

void file_reader_v0100::read_contents() {
  cout << "v1.0 파일 본문 읽기" << endl;
}

class file_reader_v0200 : public file_reader_original {
public:
  virtual void read_contents() override;
};

void file_reader_v0200::read_contents() {
  cout << "v2.0 파일 본문 읽기" << endl;
}


file_reader_original* file_reader_original::get_reader_instance() {
  file_reader_original* reader = nullptr;

  switch (file_reader_original::read_header()) {
  case 1:
    reader = new file_reader_v0100();
    break;
  case 2:
  default:
    reader = new file_reader_v0200();
    break;
  }

  return reader;
}



int main(void) {

  file_reader_original* reader = nullptr;

  reader = file_reader_original::get_reader_instance();
  if (nullptr != reader) {
    reader->read_contents();
    delete reader;
  }

  return 0;
}

 

v1.0 파일 본문 읽기

 

https://www.w3schools.com/cpp/cpp_polymorphism.asp

 

W3Schools.com

W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

www.w3schools.com

 

 

오버라이딩

함수 재정의

시그니처는 그대로 유지하면서 부모 클래스에 정의된 함수를 자식 클래스에서 재정의하는 것

 

오버라이딩 함수 호출과 네임스페이스 활용

#include <iostream>
using namespace std;

class character {
public:
  character() : hp(100), power(100) {};

protected:
  int hp;
  int power;
};

//character 클래스를 상속 받은 player 클래스
class player : public character {
public:
  player() {};
};

//기본 Monster 클래스
class monster {
public:
  monster() {};
  void get_damage(int _damage) {};
  void attack(player target_player) {};
  void attack_special(player target_player);
};

void monster::attack_special(player target_player) {
  cout << "기본 공격 : 데미지 - 10 hp" << endl;
}

//몬스터 A는 기본 Monster 클래스로부터 상속
class monster_a : public monster, character {
public:
  //상속받은 함수 오버라이딩 
  void attack_special(player target_player);
};

void monster_a::attack_special(player target_player) {
  cout << "인텡글 공격 : 데미지 - 15 hp" << endl;
}

//몬스터 B는 기본 Monster 클래스로부터 상속
class monster_b : public monster, character {
public:
  //상속받은 함수 오버라이딩
  void attack_special(player target_player);
};

void monster_b::attack_special(player target_player) {
  cout << "가상 공격 : 데미지 - 0 hp" << endl;
}

//몬스터 C는 기본 Monster 클래스로부터 상속
class monster_c : public monster, character {
public:
  //상속받은 함수 오버라이딩
  void attack_special(player target_player);
};

void monster_c::attack_special(player target_player) {
  cout << "강력 뇌전 공격 : 데미지 - 100 hp" << endl;
}

int main() {
  player player_1;

  monster_a forest_monster;
  monster_b tutorial_monster;
  monster_c boss_monster;

  cout << "오버라이딩된 공격" << endl;
  tutorial_monster.attack_special(player_1);
  forest_monster.attack_special(player_1);
  boss_monster.attack_special(player_1);

  cout << endl << "기본(monster 클래스) 공격" << endl;
  tutorial_monster.monster::attack_special(player_1);
  forest_monster.monster::attack_special(player_1);
  boss_monster.monster::attack_special(player_1);

  return 0;
}

 

오버라이딩된 공격
가상 공격 : 데미지 - 0 hp
인텡글 공격 : 데미지 - 15 hp
강력 뇌전 공격 : 데미지 - 100 hp

기본(monster 클래스) 공격
기본 공격 : 데미지 - 10 hp
기본 공격 : 데미지 - 10 hp
기본 공격 : 데미지 - 10 hp

 

가상 함수

멤버 함수 이름 앞에 virtual 키워드로 선언하면 됨

 

가상 함수를 활용한 오버라이딩 호출 변화

#include <iostream>
using namespace std;

class character {
public:
  character() : hp(100), power(100)
  {};
  void get_damage(int _damage) {};

protected:
  int hp;
  int power;
};

//Player 클래스
class player : public character {
public:
  player() {};
};

//기본 Monster 클래스
class monster {
public:
  monster() {};
  void attack(player target_player) {};
  virtual void attack_special(player target_player);
};

void monster::attack_special(player target_player) {
  cout << "기본 공격 : 데미지 - 10 hp" << endl;
}

//몬스터 A는 기본 Monster 클래스로부터 상속
class monster_a : public monster, character {
public:
  //상속받은 함수 오버라이딩 
  virtual void attack_special(player target_player) override;
};

void monster_a::attack_special(player target_player) {
  cout << "인텡글 공격 : 데미지 - 15 hp" << endl;
}

//몬스터 B는 기본 Monster 클래스로부터 상속
class monster_b : public monster, character {
public:
  //상속받은 함수 오버라이딩
  virtual void attack_special(player target_player) override;
};

void monster_b::attack_special(player target_player) {
  cout << "가상 공격 : 데미지 - 0 hp" << endl;
}

//몬스터 C는 기본 Monster 클래스로부터 상속
class monster_c : public monster, character {
public:
  //상속받은 함수 오버라이딩
  virtual void attack_special(player target_player) override;
};

void monster_c::attack_special(player target_player) {
  cout << "강력 뇌전 공격 : 데미지 - 100 hp" << endl;
}

int main() {
  player player_1;

  monster_a forest_monster;

  monster& mon = forest_monster;
  monster_a& mon_a = forest_monster;

  cout << endl << "부모 클래스 레퍼런스 후 공격" << endl;
  mon.attack_special(player_1);

  cout << endl << "자식 클래스 레퍼런스 후 공격" << endl;
  mon_a.attack_special(player_1);

  cout << endl << "범위 연산자 활용 공격" << endl;
  mon_a.monster::attack_special(player_1);

  return 0;
}

 

부모 클래스 레퍼런스 후 공격
인텡글 공격 : 데미지 - 15 hp

자식 클래스 레퍼런스 후 공격
인텡글 공격 : 데미지 - 15 hp

범위 연산자 활용 공격
기본 공격 : 데미지 - 10 hp

 

부모 클래스 변수로 자식 클래스 타입을 참조하면

기능을 호출했을 때, 부모 클래스의 기능이 호출 됨

 

단 virtual 선언된 '가상 함수'의 경우는 다름

가상 함수를 오버라이딩하면

부모 클래스 변수로 자식 클래스 타입을 참조하더라도

기능을 호출했을 때 자식 클래스의 기능이 호출된다.

 

 

생성자: 객체가 생성된 직후에 자동으로 호출되는 함수

#include <iostream>
using namespace std;

class character {
public:
  character() {
    cout << "character 클래스 생성자" << endl;
  };
};

int main() {
  character player;
  return 0;
}

 

갑을 전달받는 생성자

#include <iostream>
#include <random>
using namespace std;

class character {
public:
  character() {
    cout << "character 클래스 생성자" << endl;
  };
};

class monster {
public:
  monster() {
    cout << "monster 클래스 생성자" << endl;
  };
};

//몬스터 A는 기본 Monster 클래스로부터 상속
class monster_a : public monster, character {
public:
  monster_a() {
    cout << "monster_a 클래스 생성자" << endl;
  };

  monster_a(int x, int y) : location{ x, y } {
    cout << "monster_a 클래스 생성자 (매개변수 추가)" << endl;
  };

  void show_location() {
    cout << "위치(" << location[0] << " , " << location[1] << ")" << endl;
  };

private:
  int location[2];
};

int main() {
  monster_a forest_monster;
  forest_monster.show_location();
  monster_a wood_monster(10, 25);
  wood_monster.show_location();

  return 0;
}

 

monster 클래스 생성자
character 클래스 생성자
monster_a 클래스 생성자
위치(-858993460 , -858993460)
monster 클래스 생성자
character 클래스 생성자
monster_a 클래스 생성자 (매개변수 추가)
위치(10 , 25)

 

생성자에서 다른 생성자 호출하기

#include <iostream>
#include <random>
using namespace std;

class character {
public:
  character() {
    cout << "character 클래스 생성자" << endl;
  };
};

class monster {
public:
  monster() {
    cout << "monster 클래스 생성자" << endl;
  };
};

//몬스터 A는 기본 Monster 클래스로부터 상속
class monster_a : public monster, character {
public:
  monster_a() {
    cout << "monster_a 클래스 생성자" << endl;
    monster_a(10, 10);
  };

  monster_a(int x, int y) : location{ x, y } {
    cout << "monster_a 클래스 생성자 (매개변수 추가)" << endl;
  };
  void show_location() {
    cout << "위치(" << location[0] << " , " << location[1] << ")" << endl;
  };

private:
  int location[2];
};

int main() {
  monster_a forest_monster;
  forest_monster.show_location();

  return 0;
}

 

monster 클래스 생성자
character 클래스 생성자
monster_a 클래스 생성자
monster 클래스 생성자
character 클래스 생성자
monster_a 클래스 생성자 (매개변수 추가)
위치(-858993460 , -858993460)

 

 

멤버 변수 초기화

 

일반 멤버 변수 초기화

ㄴ직접 초기화 구문 사용

ㄴ 복사 초기화

 

레퍼런스 멤버 변수와 상수 멤버 변수 초기화

정적 멤버 변수 초기화

ㄴ클래스에 선언한 정적 변수는 전역 범위에서 초기화

 

멤버 변수 초기화(문법 요약)

class monster_b : public monsterm character {
public:
    monster_b(player & attack_target)
            : monster_type("일반"),    // 1 직접 초기화
            location{0, 0},            // 2 유니폼 초기화
            unique_id(++total_count),  // 3 상수 변수 초기화
            target(attack_target){     // 4 레퍼런스 변수 초기화
            difficult_level = 10;      // 5 복사 초기화
            quiz = new char[1024];     // 6 동적 메모리 할당
          };

private:
    string monster_type;               // 7 멤버 변수 목록
    int location[2];
    static int total_count;
    const int unique_id;
    player &target;
    int difficult_level;
    char *quiz;
};
int monster_b::total_count = 0;        // 8 정적 변수 초기화

 

복사 생성자

 

같은 클래스의 객체를 2개 생성

#include <iostream>
#include <string>
using namespace std;

class character {
public:
  character() : hp(100), power(100) {
  };

  void get_damage(int _damage) {};
protected:
  int hp;
  int power;
};

//Player 클래스
class player : public character {
public:
  player() {};
};

//기본 Monster 클래스
class monster {
public:
  void attack(player target_player) {};
  virtual void attack_special(player target_player);
};

void monster::attack_special(player target_player) {
  cout << "기본 공격 : 데미지 - 10 hp" << endl;
}


//몬스터 A는 기본 Monster 클래스로부터 상속
class monster_b : public monster, character {
public:
  monster_b(player& attack_target)
    : monster_type("일반"),         // 직접 초기화
    location{ 0,0 },                // 유니폼 초기화
    unique_id(++total_count),       // 상수 변수 초기화
    target(attack_target) {         // 레버런스 변수 초기화
    difficult_level = 10;           // 복사초기화
    quiz = new char[1024];          // 동적 메모리 할당
  };
  
  // 생성자 앞에 물결 붙은 애: 소멸자
  // 생성자는 인스턴스가 생성될 때 자동으로 호출되는 함수
  // 소멸자는 인스턴스가 소멸될 때 자동으로 호출되는 함수
  ~monster_b() {
    delete[]quiz;
    total_count--;
  };

  void set_quiz(const char* new_quiz) { strcpy_s(quiz, 1024, new_quiz); };
  void set_type(string type) { monster_type = type; };
  void set_difficult_level(int level) { difficult_level = level; };
  void set_location(int x, int y) { location[0] = x; location[1] = y; };
  char* get_quiz() { return quiz; };
  string get_type() { return monster_type; };
  int get_difficult_level() { return difficult_level; };
  int get_x_location() { return location[0]; };
  int get_y_location() { return location[1]; };

private:
  const int unique_id;
  player& target;
  static int total_count;
  char* quiz;
  string monster_type;
  int difficult_level;
  int location[2];
};

int monster_b::total_count = 0; // 정적 변수 초기화

int main() {
  player first_player;
  monster_b first_mon(first_player);
  first_mon.set_quiz("아침에 네발, 점심에는 두발, 저녁에는 두발인 것은?");
  first_mon.set_difficult_level(100);
  first_mon.set_type("수수께끼 몬스터");
  first_mon.set_location(30, 30);

  monster_b second_mon(first_player);
  second_mon.set_quiz("문이 뒤집어 지면 무엇이 될까?");
  second_mon.set_location(45, 50);

  cout << "[" << first_mon.get_x_location() << " , " << first_mon.get_y_location()
    << "] 첫번째 몬스터(" << first_mon.get_type() << " - "
    << first_mon.get_difficult_level()
    << ")가 내는 수수께끼 : " << first_mon.get_quiz() << endl;
  cout << "[" << second_mon.get_x_location() << " , " << second_mon.get_y_location()
    << "] 두번째 몬스터(" << second_mon.get_type() << " - "
    << second_mon.get_difficult_level()
    << ")가 내는 수수께끼 : " << second_mon.get_quiz() << endl;

  return 0;
}

 

[30 , 30] 첫번째 몬스터(수수께끼 몬스터 - 100)가 내는 수수께끼 : 아침에 네발, 점심에는 두발, 저녁에는 두발인 것은?
[45 , 50] 두번째 몬스터(일반 - 10)가 내는 수수께끼 : 문이 뒤집어 지면 무엇이 될까?

 

얕은 복사

동적으로 할당된 멤버 변수는 메모리를 할당하지 않고 동적 메모리를 가리키는 포인터 변수를 복사하므로 주소값만 복사됨

 

깊은복사

포인터 변수끼리 대입했을 때 메모리가 새롭게 할당되게 한 것

객체를 같은 클래스로 생성한 객체로 초기화하면 얕은 복사를 수행하는 기본 복사 생성자가 생성되고 호출됨

 

#include <iostream>
#include <string>
using namespace std;

class character {
public:
  character() : hp(100), power(100) {
  };

  void get_damage(int _damage) {};
protected:
  int hp;
  int power;
};

//Player 클래스
class player : public character {
public:
  player() {};
};

//기본 Monster 클래스
class monster {
public:
  void attack(player target_player) {};
  virtual void attack_special(player target_player);
};

void monster::attack_special(player target_player) {
  cout << "기본 공격 : 데미지 - 10 hp" << endl;
}


//몬스터 A는 기본 Monster 클래스로부터 상속
class monster_b : public monster, character {
public:
  monster_b(player& attach_target)
    : monster_type("일반"),       // 직접 초기화
    location{ 0,0 },              // 유니폼 초기화
    unique_id(++total_count),     // 상수 변수 초기화
    target(attach_target) {       // 레버런스 변수 초기화
    difficult_level = 10;         // 복사초기화
    quiz = new char[1024];        // 동적 메모리 할당
  };

  ~monster_b() {
    delete[]quiz;
    total_count--;
  };

  monster_b(const monster_b& ref);

  //상속받은 함수 오버라이딩 
  virtual void attack_special(player target_player) override {
    cout << "가상 공격 : 데미지 - 0 hp" << endl;
  };

  void set_quiz(const char* new_quiz) { strcpy_s(quiz, 1024, new_quiz); };
  void set_type(string type) { monster_type = type; };
  void set_difficult_level(int level) { difficult_level = level; };
  void set_location(int x, int y) { location[0] = x; location[1] = y; };
  char* get_quiz() { return quiz; };
  string get_type() { return monster_type; };
  int get_difficult_level() { return difficult_level; };
  int get_x_location() { return location[0]; };
  int get_y_location() { return location[1]; };

private:
  const int unique_id;
  player& target;
  static int total_count;
  char* quiz;
  string monster_type;
  int difficult_level;
  int location[2];
};

int monster_b::total_count = 0; // 정적 변수 초기화

// 어떤 대상을 내게 참조시키면, 그때마다 new를 해서
// 새로운 메모리를 할당받을 것이다.
// 그러면 메모리가 서로 겹치는 일이 없다.
monster_b::monster_b(const monster_b& ref) : unique_id(++total_count), target(ref.target) {
  quiz = new char[1024];
  strcpy_s(quiz, strlen(ref.quiz) + 1, ref.quiz);
  monster_type = ref.monster_type;
  difficult_level = ref.difficult_level;
  location[0] = ref.location[0];
  location[1] = ref.location[1];
}

int main() {
  player first_player;
  monster_b first_mon(first_player);
  first_mon.set_quiz("아침에 네발, 점심에는 두발, 저녁에는 두발인 것은?");
  first_mon.set_difficult_level(100);
  first_mon.set_type("수수께끼 몬스터");
  first_mon.set_location(30, 30);

  monster_b second_mon = first_mon;
  second_mon.set_quiz("문이 뒤집어 지면 무엇이 될까?");
  second_mon.set_location(45, 50);


  cout << "[" << first_mon.get_x_location() << " , " << first_mon.get_y_location()
    << "] 첫번째 몬스터(" << first_mon.get_type() << " - "
    << first_mon.get_difficult_level()
    << ")가 내는 수수께끼 : " << first_mon.get_quiz() << endl;
  cout << "[" << second_mon.get_x_location() << " , " << second_mon.get_y_location()
    << "] 두번째 몬스터(" << second_mon.get_type() << " - "
    << second_mon.get_difficult_level()
    << ")가 내는 수수께끼 : " << second_mon.get_quiz() << endl;

  return 0;
}

 

소멸자

생성자와 반대 역할

객체가 소멸할 때 필요한 메모리 해제나 외부 환경을 객체 생성 이전 상태로 변경하는 등의 일을 진행

 

소멸자 선언

~클래스_이름()

 

소멸자 정의

#include <iostream>
#include <random>
using namespace std;

class character {
public:
  character() {
    cout << "character 클래스 생성자" << endl;
  };
  ~character() {
    cout << "charactor 클래스 소멸자" << endl;
  }
};

class monster {
public:
  monster() {
    cout << "monster 클래스 생성자" << endl;
  };
    ~monster() {
    cout << "monster 클래스 소멸자" << endl;
  };
};

//몬스터 A는 기본 Monster 클래스로부터 상속
class monster_a : public monster, character {
public:
  monster_a() {
    cout << "monster_a 클래스 생성자" << endl;
  };

  ~monster_a() {
    cout << "monster_a 클래스 소멸자" << endl;
  }
};

int main() {
  monster_a forest_monster;
  return 0;
}

 

monster 클래스 생성자
character 클래스 생성자
monster_a 클래스 생성자
monster_a 클래스 소멸자
charactor 클래스 소멸자
monster 클래스 소멸자

 

부모 클래스 변수로 자식 인스턴스를 참조하면

기본적으로 부모의 기능 사용

 

단, virtual 키워드를 사용해서 만든 가상함수를

오버라이딩 한 경우에는

부모 클래스 변수로 자식 인스턴스를 참조해도

자식의 기능을 사용한다

 

 

this 포인터

객체 내부에서 객체 자신을 가리키는 키워드

파이썬의 self와 비슷

 

멤버 변수와 매개변수 이름이 같을 때 구분

자기 자신을 반환할 때(매서드 체이닝)

현재 객체의 주소가 필요할 때

 

static 멤버 함수에서는 사용 불가 -> 객체에 속하지 않음

 

#include <iostream>
using namespace std;

class bank {
private:
  int safe; //금고
  string bank_name;

public:
  bank(string name) : bank_name(name) { safe = 0; };  //기본 생성자  
  ~bank() {};
  void use_counter(int _in, int _out);  //입출금 창구 함수 
};

void bank::use_counter(int _in, int _out) {
  safe += _in;
  safe -= _out;
  cout << bank_name << " 처리 - 입금: " << _in << ", 출금: " << _out << endl;
}

int main() {
  bank rich_bank("부유한 은행"), global_bank("세계적 은행");
  rich_bank.use_counter(10, 10);
  global_bank.use_counter(20, 5);
  return 0;
}

 

부유한 은행 처리 - 입금: 10, 출금: 10
세계적 은행 처리 - 입금: 20, 출금: 5

 

this 포인터는 멤버 함수 내에서 자동으로 생성되어 해당 함수가 속한 객체의 주소를 가리킴

 

#include <iostream>
#include <string>
using namespace std;

class bank {
private:
  int safe; //금고
  string bank_name;

public:
  bank(string name) : bank_name(name) { safe = 0; };  //기본 생성자  
  ~bank() {};
  void use_counter(int _in, int _out);  //입출금 창구 함수
  void transfer_account(int safe);      // 계좌 변경 함수
  void reset_account();                 // 계좌 초기화
  int get_safe() { return safe; };      // 금고 금액 반환
};

void bank::use_counter(int _in, int _out) {
  safe += _in;
  safe -= _out;
  cout << bank_name << " 처리 - 입금: " << _in << ", 출금: " << _out << endl;
}

void bank::transfer_account(int safe) {
  this->safe = safe;
  cout << bank_name << "으로 계좌 이동: " << safe << endl;
}

void bank::reset_account() {
  this->safe = 0;
  cout << bank_name << " 계좌가 초기화 되었습니다." << endl;
}

int main() {
  bank rich_bank("부유한 은행"), global_bank("세계적 은행");
  rich_bank.use_counter(50, 10);

  global_bank.transfer_account(rich_bank.get_safe());
  rich_bank.reset_account();
  
  return 0;
}

 

함수 체이닝

여러 함수를 연이어 호출하는 방식

멤버 함수가 객체를 반환하고 해당 객체에서 다시 멤버 함수를 호출하는 방식으로 이루어짐

 

함수 호출문 뒤에다가 함수 호출문을 이어 쓰는 기법

 

ex)

사람 밥먹기().잠자기()

 

#include <iostream>
#include <string>
using namespace std;

class bank {
private:
  int safe; //금고
  string bank_name;

public:
  bank(string name) : bank_name(name) { safe = 0; };  //기본 생성자  
  ~bank() {};
  void use_counter(int _in, int _out);  //입출금 창구 함수
  void transfer_account(int safe);      // 계좌 변경 함수
  void reset_account();                 // 계좌 초기화
  int get_safe() { return safe; };      // 금고 금액 반환
  bank& deposit_interest(int interest); // 이자 입금
  bank& withdraw_utility(int utility);  // 공과금 출금
  bank& withdraw_tax(int tax);          // 세금 출금
  
  string get_bank_name() { return bank_name; };
};

void bank::use_counter(int _in, int _out) {
  safe += _in;
  safe -= _out;
  cout << bank_name << " 처리 - 입금: " << _in << ", 출금: " << _out << endl;
}

void bank::transfer_account(int safe) {
  this->safe = safe;
  cout << bank_name << "으로 계좌 이동: " << safe << endl;
}

void bank::reset_account() {
  this->safe = 0;
  cout << bank_name << " 계좌가 초기화 되었습니다." << endl;
}

bank& bank::deposit_interest(int interest) {
  safe += interest;
  cout << bank_name << " 이자 지급: " << interest << endl;
  return *this;
}

bank& bank::withdraw_utility(int utility) {
  safe -= utility;
  cout << bank_name << " 공과금 납부: " << utility << endl;
  return *this;
}

bank& bank::withdraw_tax(int tax) {
  safe -= tax;
  cout << bank_name << " 세금 납부: " << tax << endl;
  return *this;
}

int main() {
  bank rich_bank("부유한 은행"), global_bank("세계적 은행");
  rich_bank.use_counter(50, 10);
  cout << endl;

  global_bank.transfer_account(rich_bank.get_safe());
  rich_bank.reset_account();
  cout << endl;

  // 함수 체이닝 호출(함수가 차례로 호출됨)
  global_bank.deposit_interest(10).withdraw_utility(1).withdraw_tax(2);
  cout << endl;
  cout << global_bank.get_bank_name() << "잔액: " << global_bank.get_safe() << endl;

  return 0;
}

 

부유한 은행 처리 - 입금: 50, 출금: 10

세계적 은행으로 계좌 이동: 40
부유한 은행 계좌가 초기화 되었습니다.

세계적 은행 이자 지급: 10
세계적 은행 공과금 납부: 1
세계적 은행 세금 납부: 2

세계적 은행잔액: 47