[C++] 씹어먹는 C++ - <4 - 3. 복사 생성자, 소멸자>

Kim Dongil·2022년 11월 27일
0

C++

목록 보기
3/23
#include <string.h>
#include <iostream>

class Marine {
  int hp;                // 마린 체력
  int coord_x, coord_y;  // 마린 위치
  int damage;            // 공격력
  bool is_dead;
  char* name;  // 마린 이름

 public:
  Marine();                                       // 기본 생성자
  Marine(int x, int y, const char* marine_name);  // 이름까지 지정
  Marine(int x, int y);  // x, y 좌표에 마린 생성
  ~Marine();

  int attack();                       // 데미지를 리턴한다.
  void be_attacked(int damage_earn);  // 입는 데미지
  void move(int x, int y);            // 새로운 위치

  void show_status();  // 상태를 보여준다.
};
Marine::Marine() {
  hp = 50;
  coord_x = coord_y = 0;
  damage = 5;
  is_dead = false;
  name = NULL;
}
Marine::Marine(int x, int y, const char* marine_name) {
  name = new char[strlen(marine_name) + 1];
  strcpy(name, marine_name);

  coord_x = x;
  coord_y = y;
  hp = 50;
  damage = 5;
  is_dead = false;
}
Marine::Marine(int x, int y) {
  coord_x = x;
  coord_y = y;
  hp = 50;
  damage = 5;
  is_dead = false;
  name = NULL;
}
void Marine::move(int x, int y) {
  coord_x = x;
  coord_y = y;
}
int Marine::attack() { return damage; }
void Marine::be_attacked(int damage_earn) {
  hp -= damage_earn;
  if (hp <= 0) is_dead = true;
}
void Marine::show_status() {
  std::cout << " *** Marine : " << name << " ***" << std::endl;
  std::cout << " Location : ( " << coord_x << " , " << coord_y << " ) "
            << std::endl;
  std::cout << " HP : " << hp << std::endl;
}
Marine::~Marine() {
  std::cout << name << " 의 소멸자 호출 ! " << std::endl;
  if (name != NULL) {
    delete[] name;
  }
}
int main() {
  Marine* marines[100];

  marines[0] = new Marine(2, 3, "Marine 2");
  marines[1] = new Marine(1, 5, "Marine 1");

  marines[0]->show_status();
  marines[1]->show_status();

  std::cout << std::endl << "마린 1 이 마린 2 를 공격! " << std::endl;

  marines[0]->be_attacked(marines[1]->attack());

  marines[0]->show_status();
  marines[1]->show_status();

  delete marines[0];
  delete marines[1];
}
  • new
    객체를 동적으로 생성하면서와 동시에 자동으로 생성자도 호출한다.
    리턴하는 것이 바로 생성된 객체의 주소값, 따라서 & 를 붙일 필요가 없다

  • class 내부에 있는 const
    클래스 안에 멤버 변수와 함수들한테 const를 붙임으로써 해당 함수에서 객체의 멤버를 변경할 수 없도록 한다

  • 마린 이름만들때 name 그리고 Marines *marines[100] 에서 포인터를 사용한 이유
    마린 객체를 동적으로 생성하기 위함

  • name = new char [strlen(pc.name) + 1]
    이 부분에서 +1을 하는 이유 = 널문자 \0을 넣기 위해서이다.
    name 은 그냥 일반 포인터이므로 sizeof(name) 을 찍어보면 배열의 크기가 아니라 4 가 나올 것.
    \따라서 + 1 을 전달해야 한다.

  • 생성자는 어떤 객체가 생성과 동시에 유효함을 보장하는 역할을 한다.

class Person {
    int age;
    int height;
}
Person p = new Person();

현재 Person p는 나이가 0 이고 키도 0 입니다. 이런 사람은 존재할 수 없겠죠? 그래서 이런 객체는 유효하지 않다고 합니다. 이 문제를 해결하기 위해 생성자를 이용합니다.

Marine(int x, int y); 처럼 마린을 생성하는 함수가 있는데 따로

Marine::Marine() {
	hp = 50;
	coord_x = coord_y = 0;
	damage = 5;
	is_dead = false;
}

라는 기본생성자를 생성해줘야 하는 이유는 기본 생성자를 정의하지 않으면 컴파일러가 알아서 하나 만들어주는데 (디폴트 생성자), 이 생성자는 데이터 멤버들을 디폴트로 초기화 해줍니다. 예를들어 위 경우 hp 나 damage 가 모두 0 이 됩니다.

  • Marin marin[100]; 이 아닌 Marin *marin[100]; 으로 한 이유
    Marin *marin[100] 의 경우 실제 객체는 동적으로 할당해야 한다. 반면에 Marin marin[20] 은 실제 객체 20개가 생성이 된다
    첫 번째의 경우 동적으로 할당하지 않을 경우 생성되어 있는 마린은 없다
    예를 들어서 마린 객체의 크기가 30 바이트라고 한다면
    Marin marin[100] 의 경우 3000 바이트를 차지한다 (3 킬로바이트)
    하지만 Marin *marin[100] 의 경우 단순히 주소값 배열이므로 8 * 100 = 800 바이트만 차지하게 된다
    만일 마린을 실제로 생성하게 된다면 30 바이트씩 추가된다

1. 아래와 같은 문자열 클래스를 완성해보세요

(난이도 : 中)

#include <iostream>

class string {
	char* str;
	int len;

public:
	string(char c, int n);  // 문자 c 가 n 개 있는 문자열로 정의
	string(const char* s);
	string(const string& s);
	~string();

	void add_string(const string& s);   // str 뒤에 s 를 붙인다.
	void copy_string(const string& s);  // str 에 s 를 복사한다.
	int strlen();                       // 문자열 길이 리턴	
	void print();
};

string::string(char c, int n) {
	len = n;
	str = new char[len];
	for (int i = 0; i < len; i++) {
		str[i] = c;
	}
	str[len] = NULL;
}
string::string(const char* s) {
	len = 0;
	while (s[len]) {
		len++;
	}
	str = new char[len];
	for (int i = 0; i < len; i++) {
		str[i] = s[i];
	}
}
string::string(const string& s) {
	len = s.len;
	str = new char[len];
	for (int i = 0; i < len; i++) {
		str[i] = s.str[i];
	}
}
string::~string() {
	if (str) {
		delete[] str;
	}
}

void string::add_string(const string& s) {
	char* tmp = new char[len + s.len];
	int i;
	for (i = 0; i < len; i++) tmp[i] = str[i];
	for (int j = 0; i < len + s.len; i++, j++) tmp[i] = s.str[j];
	len += s.len, delete[] str, str = tmp;
}

void string::copy_string(const string& s) {
	len = s.len;
	delete[] str;
	str = new char[len];
	for (int i = 0; i < len; i++) {
		str[i] = s.str[i];
	}
}

int string::strlen() {
	return len;
}
void string::print()
{
	for (int i = 0; i < len; i++) std::cout << str[i];
}


int main() {
	string str1("ABCEDFGHIJKL");
	string str2(str1);
	string add("mnopqrstuvwxyz");
	str1.print(), std::cout << std::endl, str2.print(), std::cout << std::endl;
	add.print(), std::cout << std::endl;
	std::cout << str1.strlen() << ", " << add.strlen() << std::endl;
	str1.add_string(add);
	str2.copy_string(str1);
	str1.print(), std::cout << std::endl, str2.print(), std::cout << std::endl;
	std::cout << str1.strlen() << ", " << str2.strlen() << std::endl;

	return 0;
}

씹어먹는 C++ - <4 - 3. 스타크래프트를 만들자 ① (복사 생성자, 소멸자)>
생성자를 만드는 이유가 먼가요?

0개의 댓글

관련 채용 정보