객체
변수들과 참고 자료들로 이루어진 소프트웨어 덩어리
#include <iostream>
class Animal {
private:
int food;
int weight;
public:
void set_animal(int _food, int _weight) {
food = _food;
weight = _weight;
}
void increase_food(int inc) {
food += inc;
weight += (inc / 3);
}
void view_stat() {
std::cout << "이 동물의 food : " << food << std::endl;
std::cout << "이 동물의 weight : " << weight << std::endl;
}
}; // 세미콜론 잊지 말자!
int main() {
Animal animal;
animal.set_animal(100, 50);
animal.increase_food(30);
animal.view_stat();
return 0;
}

Animal 클래스
멤버변수와 멤버함수는 인스턴스가 만들어져야 존재하는 것
멤버 변수 (member variable) : food, weight
멤버 함수 (member function) : set_animal, increase_food, view_stat
접근지시자 : 외부에서 멤버들에 접근할 수 있냐 없냐를 지시
private 객체 내에서 보호받고 있기 때문에, 자기 객체 안에서는 접근 가능하지만 객체 외부에서는 접근할 수 없음
// 같은 객체 안에서 food와 weight에 접근 가능
void set_animal(int _food, int _weight) {
food = _food;
weight = _weight;
}
// 객체 밖에서 인위적으로 food에 접근 불가능
int main() {
Animal animal;
animal.food = 100;
}
cpp에서는 같은 이름의 함수를 호출 했을 때, 사용하는 인자를 보고 구분
즉, 함수의 이름이 같더라도 인자가 다르면 다른 함수
/* 함수의 오버로딩 */
#include <iostream>
void print(int x) { std::cout << "int : " << x << std::endl; }
void print(char x) { std::cout << "char : " << x << std::endl; }
void print(double x) { std::cout << "double : " << x << std::endl; }
int main() {
int a = 1;
char b = 'c';
double c = 3.2f;
print(a);
print(b);
print(c);
return 0;
}

[C++ 컴파일러에서 함수를 오버로딩하는 과정]
char, unsigned char, short는 int로 변환Unsinged short는 int의 크기에 따라 int 혹은 unsigned int로 변환Float는 double로 변환Enum은 int로 변환Enum도 임의의 숫자 타입으로 변환 (ex. enum -> double)0은 포인터나 숫자 타입으로 변환된 0은 포인터 타입이나 숫자 타입으로 변환void 포인터로 변환생성자 : 객체 생성 시 자동으로 호출되는 함수
#include <iostream>
class Date {
int year_;
int month_; // 1 부터 12 까지.
int day_; // 1 부터 31 까지.
public:
void SetDate(int year, int month, int date);
void AddDay(int inc);
void AddMonth(int inc);
void AddYear(int inc);
// 해당 월의 총 일 수를 구한다.
int GetCurrentMonthTotalDays(int year, int month);
void ShowDate();
Date(int year, int month, int day) {
year_ = year;
month_ = month;
day_ = day;
}
};
// 생략
void Date::AddYear(int inc) { year_ += inc; }
void Date::ShowDate() {
std::cout << "오늘은 " << year_ << " 년 " << month_ << " 월 " << day_
<< " 일 입니다 " << std::endl;
}
int main() {
Date day(2011, 3, 1);
day.ShowDate();
day.AddYear(10);
day.ShowDate();
return 0;
}

// 아래와 같이 Date의 생성자 정의
Date(int year, int month, int day)
// 생성자는 객체를 생성할 때, 위 함수에서 정의한 인자에 맞게 써준다면 (함수를 호출하듯이), 위 생성자를 호출하며 객체를 생성할 수 있게 됨
Date day(2011, 3, 1);
즉, 위의 코드는 "Date 클래스의 day객체를 만들면서 생성자 Date(int year, int month, int day)를 호출한다" 는 의미!
Date day(2011, 3, 1); // 암시적 방법 (implicit)
Date day = Date(2012, 3, 1); // 명시적 방법 (explicit)
디폴트 생성자 : 인자를 하나도 가지지 않는 생성자이며, 클래스에서 사용자가 어떠한 생성자도 명시적으로 정의하지 않았을 경우 컴파일러가 자동으로 추가해주는 생성자
Date day;
따라서 생성자를 정의하지 않고 위와 같이 작성하더라도 생성자가 호출됨.
(물론, 컴파일러가 자동으로 생성할 때는 아무런 일도 하지 않아 쓰레기 값이 나옴)
// 디폴트 생성자 정의해보기
#include <iostream>
class Date {
int year_;
int month_; // 1 부터 12 까지.
int day_; // 1 부터 31 까지.
public:
void ShowDate();
Date() { // 디폴트 생성자 정의
year_ = 2012;
month_ = 7;
day_ = 12;
}
};
생성자 역시 함수이기 때문에, 마찬가지로 함수의 오버로딩이 적용될 수 있음.
new는 객체를 동적으로 생성하면서 동시에 자동으로 생성자도 호출해줌
// Marine(2,3) 과 Marine(3,5) 라는 생성자를 자동으로 호출
marines[0] = new Marine(2, 3);
marines[1] = new Marine(3, 5);
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;
}
name에 마린의 이름을 넣어줄 때, name을 동적으로 생성해서 문자열을 복사했음. 그럼 이렇게 동적으로 할당된 char 배열에 대한 delete는 언제 이루어질까? -> 명확히 delete를 지정하지 않는 한 자동으로 delete가 되는 경우는 없음. = 메모리 누수 발생
그런데 c++에는 main함수 끝에서 마린이 delete될 때, 즉 우리가 생성했던 객체가 소멸될 때 자동으로 호출되는 함수가 있음. 그것이 바로 소멸자(Destructor)
~만 붙여주면 됨 (ex. ~Marine();)디폴트 생성자가 있었던 것 처럼, 소멸자도 "디폴트 소멸자"가 존재. 물론, 디폴트 소멸자 내부에선 아무런 작업도 수행하지 않음
복사 생성자 : 자신과 같은 클래스 타입의 다른 객체에 대한 레퍼런스를 인수로 전달받아, 그 참조를 가지고 자신을 초기화
복사생성자를 이용한 대입은 깊은 복사를 통한 복사이기 때문에, 새롭게 생성되는 객체가 원본 객체와 같으면서도 완전한 독립성을 가지게 해줌
T(const T& a); // 복사 생성자의 표준적인 정의
Photon_Cannon(const Photon_Cannon& pc);
다른 T의 객체 a를 상수 레퍼런스로 받음.
여기서 a가 const이기 때문에, 복사 생성자 내부에서 a의 데이터를 변경할 수 없고 오직 새롭게 초기화되는 인스턴스 변수에만 복사할 수 있음.
Photon_Cannon::Photon_Cannon(const Photon_Cannon& pc) {
std::cout << "복사 생성자 호출 !" << std::endl;
hp = pc.hp;
shield = pc.shield;
coord_x = pc.coord_x;
coord_y = pc.coord_y;
damage = pc.damage;
}
즉, 이처럼 복사 생성자 내부에서 pc의 인스턴스 변수에 접근해 shield, coord_x, coord_y를 초기화 할 수는 있지만 pc.coord_x = 3;과 같이 pc 값 자체는 변경 불가능
hp, shield - 값을 가리키는 포인터를 복사name - 값을 복사