#include <iostream>
class Marine {
int hp; // 마린 체력
int coord_x, coord_y; // 마린 위치
int damage; // 공격력
bool is_dead;
public:
Marine(); // 기본 생성자
Marine(int x, int y); // x, y 좌표에 마린 생성
int attack(); // 데미지를 리턴한다.
void be_attacked(int damage_earn); // 입는 데미지
void move(int x, int y); // 새로운 위치
void show_status(); // 상태를 보여준다.
};
// 아래에 집중!!
Marine::Marine() : hp(50), coord_x(0), coord_y(0), damage(5), is_dead(false) {}
Marine::Marine(int x, int y)
: coord_x(x), coord_y(y), hp(50), damage(5), is_dead(false) {}
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 *** " << std::endl;
std::cout << " Location : ( " << coord_x << " , " << coord_y << " ) "
<< std::endl;
std::cout << " HP : " << hp << std::endl;
}
int main() {
Marine marine1(2, 3);
Marine marine2(3, 5);
marine1.show_status();
marine2.show_status();
}
(생성자 이름): var1(arg1), var2(arg2) {}
var1 이름
== argv1 이름
이어도 정상적으로 동작함.생성과 초기화를 동시에 하게 됨
클래스였다면 복사 생성자 호출과 같은 효과
초기화 리스트 미사용 시: 생성을 먼저 하고 그 다음에 대입,
클래스였다면 디폴트 생성자가 호출된 뒤 대입이 수행
즉, 비용이 절감됨. 좀 더 자세히 얘기해보자.
class Foo
{
public:
Foo(std::string& str);
private:
std::string name;
}
Foo::Foo(std::string& str)
{
name = str; // 초기화가 아니라 대입!!
}
위 코드를 보면 데이터 멤버 객체에 대해 초기화
를 수행하고 대입
까지 해버리는, 즉 작업을 2번 수행하는 꼴이 됨.
멤버 초기화 리스트를 사용하면 위와 같이 작업을 2번 수행하는 게 아닌 1번만 수행해도 됨.
class Foo
{
public:
Foo(std::string& str);
private:
std::string name;
}
Foo::Foo(std::string& str) :
name(str) // 초기화만으로 str 값을 name 안에 넣게 될 수 있습니다.
{}
그런데 이때 기본 생성자를 호출해 초기화하고 싶으면 아래와 같이 쓰면 됨.
Foo::Foo(std::string& str) :
name() // 기본 생성자 호출
{}
결론부터 말하면 가능하다.
아래 코드를 보면 default_damage가 constant(상수)로 선언된 것을 볼 수 있다.
그런데 생성자를 보면 int default_damage로 받도록 되어있다.
이때 default_damage는
const int default_damage = (인자로 받은 default_damage);
와 같이 초기화된 것과 마찬가지다.
#include <iostream>
class Marine {
int hp; // 마린 체력
int coord_x, coord_y; // 마린 위치
bool is_dead;
const int default_damage; // 기본 공격력
public:
Marine(); // 기본 생성자
Marine(int x, int y); // x, y 좌표에 마린 생성
Marine(int x, int y, int default_damage);
int attack(); // 데미지를 리턴한다.
void be_attacked(int damage_earn); // 입는 데미지
void move(int x, int y); // 새로운 위치
void show_status(); // 상태를 보여준다.
};
Marine::Marine()
: hp(50), coord_x(0), coord_y(0), default_damage(5), is_dead(false) {}
Marine::Marine(int x, int y)
: coord_x(x), coord_y(y), hp(50), default_damage(5), is_dead(false) {}
Marine::Marine(int x, int y, int default_damage)
: coord_x(x),
coord_y(y),
hp(50),
default_damage(default_damage),
is_dead(false) {}
static 멤버
전역 변수 같지만 클래스 하나에만 종속되는 변수
원래 클래스 멤버는 선언만 하고 초기화할 수 없음.
예외로 const static은 클래스 코드 내부에 선언과 초기화를 동시에 가능
// static 멤버 변수의 사용
class Marine {
static int total_marine_num;
int hp; // 마린 체력
int coord_x, coord_y; // 마린 위치
bool is_dead;
const int default_damage; // 기본 공격력
public:
Marine(); // 기본 생성자
Marine(int x, int y); // x, y 좌표에 마린 생성
Marine(int x, int y, int default_damage);
int attack(); // 데미지를 리턴한다.
void be_attacked(int damage_earn); // 입는 데미지
void move(int x, int y); // 새로운 위치
void show_status(); // 상태를 보여준다.
~Marine() { total_marine_num--; }
};
// 아래와 같이 쓰지 않을 수 없음.
int Marine::total_marine_num = 0;
{class}::{static_함수}
로 호출(어떤 객체에도 속하지 않기 때문)void Marine::show_total_marine(){ ... }
으로 클래스 외부에서 함수 내용 작성함static void show_total_marine(){}
으로 선언1번
과 2번
에서 찍은 Dummy 클래스 내부의 변수 this
와 dummy의 주소값을 가진 포인터 dummyPointer
는 같은 주소값을 가진 것을 볼 수 있다.// Example program
#include <iostream>
#include <string>
using namespace std;
class Dummy{
public:
Dummy();
~Dummy();
void showThisAddress(){
// ** 1번 **
cout << "this: " << this << endl;
}
};
Dummy::Dummy(){}
Dummy::~Dummy(){}
int main()
{
Dummy dummy;
dummy.showThisAddress();
Dummy* dummyPtr;
dummyPtr = &dummy;
// ** 2번 **
cout << "dummyPointer: " << dummyPtr << endl;
return 0;
}
참고: this의 의미와 사용법
레퍼런스를 리턴하는 함수 acces_x를 통해
-> private 변수에 해당하는 x를 클래스 외부에서 변경할 수 있는 권한
이 주어진다.
// 레퍼런스를 리턴하는 함수
#include <iostream>
class A {
int x;
public:
A(int c) : x(c) {}
int& access_x() { return x; }
int get_x() { return x; }
void show_x() { std::cout << x << std::endl; }
};
int main() {
A a(5);
a.show_x(); // 5
int& c = a.access_x();
c = 4;
a.show_x(); // 4
int d = a.access_x();
d = 3;
a.show_x(); // 4
// 아래는 오류
// int& e = a.get_x();
// e = 2;
// a.show_x();
int f = a.get_x();
f = 1;
a.show_x(); // 4
}
위 코드 "아래는 오류"부분에서는 컴파일 오류가 발생하는데, 그 이유는
임시 객체(int 변수)가 생성
되어 반환된 타입을 저장함임시 객체는 레퍼런스를 가질 수 없음
상수 멤버 함수
int Marine::attack() const { return default_damage; }
그러나 많은 경우 getter를 씀(멤버 변수: private, 게터: public)
// 상수 멤버 함수
#include <iostream>
class Marine {
static int total_marine_num;
const static int i = 0;
int hp; // 마린 체력
int coord_x, coord_y; // 마린 위치
bool is_dead;
const int default_damage; // 기본 공격력
public:
Marine(); // 기본 생성자
Marine(int x, int y); // x, y 좌표에 마린 생성
Marine(int x, int y, int default_damage);
int attack() const; // 데미지를 리턴한다.
Marine& be_attacked(int damage_earn); // 입는 데미지
void move(int x, int y); // 새로운 위치
void show_status(); // 상태를 보여준다.
static void show_total_marine();
~Marine() { total_marine_num--; }
};
int Marine::total_marine_num = 0;
void Marine::show_total_marine() {
std::cout << "전체 마린 수 : " << total_marine_num << std::endl;
}
Marine::Marine()
: hp(50), coord_x(0), coord_y(0), default_damage(5), is_dead(false) {
total_marine_num++;
}
Marine::Marine(int x, int y)
: coord_x(x),
coord_y(y),
hp(50),
default_damage(5),
is_dead(false) {
total_marine_num++;
}
Marine::Marine(int x, int y, int default_damage)
: coord_x(x),
coord_y(y),
hp(50),
default_damage(default_damage),
is_dead(false) {
total_marine_num++;
}
void Marine::move(int x, int y) {
coord_x = x;
coord_y = y;
}
int Marine::attack() const { return default_damage; }
Marine& Marine::be_attacked(int damage_earn) {
hp -= damage_earn;
if (hp <= 0) is_dead = true;
return *this;
}
void Marine::show_status() {
std::cout << " *** Marine *** " << std::endl;
std::cout << " Location : ( " << coord_x << " , " << coord_y << " ) "
<< std::endl;
std::cout << " HP : " << hp << std::endl;
std::cout << " 현재 총 마린 수 : " << total_marine_num << std::endl;
}
int main() {
Marine marine1(2, 3, 5);
marine1.show_status();
Marine marine2(3, 5, 10);
marine2.show_status();
std::cout << std::endl << "마린 1 이 마린 2 를 두 번 공격! " << std::endl;
marine2.be_attacked(marine1.attack()).be_attacked(marine1.attack());
marine1.show_status();
marine2.show_status();
}