요약

초기화 방법

  1. 멤버변수 정의 시 초기화
  2. 생성자에서 초기화
  3. 생성자에서 초기화 리스트로 초기화


상수 멤버레퍼런스 멤버의 초기화,

객체의 모든 데이터 멤버가 초기화된다는 보장을 하는 이점이 있는 초기화 리스트를 사용하자.


호출 순서

초기화 리스트 > (초기화 리스트에 없는)멤버 변수 정의 시 초기화 > 생성자에서 초기화


클래스 멤버 변수

클래스 멤버 변수(Class Member Variable)

  • 특정 객체와 연결된 변수의 하나. 해당 변수의 모든 메소드(멤버 함수)에 접근이 가능


초기화 이유

생성자, 소멸자 본문에서 언급했듯이,

어떤 값인지 알지도 못하는 쓰레기값보다는

0 or -1 or NULL or “” 와 같이 초기화되지 않았음을 명시할 때


방법

  1. 생성자에서 초기화
  2. 멤버변수 정의 시 초기화
  3. 생성자에서 초기화 리스트로 초기화


1. 생성자에서 초기화

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

class unit
{
protected:
	int hp;
	int atk;
	vector<string> dropItems;
public:
	unit()
	{
		hp = 50;    // 생성자에서 초기화
		atk = 5;
		dropItems.push_back("잡템");
		dropItems.push_back("목검");
		dropItems.push_back("천옷");
	}
	void PrintInfo()
	{
		cout << "hp: " << hp << '\n';
		cout << "atk: " << atk << '\n';
		cout << "dropItems: ";
		int size = dropItems.size();
		for (int i = 0; i < size; i++)
			cout << dropItems[i] << " ";
	}
};

int main()
{
	unit monster;
	monster.PrintInfo();
}
hp: 50
atk: 5
dropItems: 잡템 목검 천옷


2. 멤버변수 정의 시 초기화

C++11 부터 멤버변수에 직접 기본 초기값 할당 가능

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

class unit
{
protected:
	int hp = 50;    // 멤버변수 정의 시 초기화
	int atk = 5;
	vector<string> dropItems{ "잡템", "목검", "천옷" };     // {} 유니폼 초기화   = 복사 초기화    () 직접 초기화
public:
	void PrintInfo()
	{
		cout << "hp: " << hp << '\n';
		cout << "atk: " << atk << '\n';
		cout << "dropItems: ";
		int size = dropItems.size();
		for (int i = 0; i < size; i++)
			cout << dropItems[i] << " ";
	}
};

int main()
{
	unit monster;
	monster.PrintInfo();
}
hp: 50
atk: 5
dropItems: 잡템 목검 천옷


3. 생성자에서 초기화 리스트로 초기화

멤버 초기화 리스트 (Member Initializer List, 이니셜라이저)

”: 변수(초기화값), …”

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

class unit
{
protected:
	int hp;
	int atk;
	vector<string> dropItems;
public:
	unit() :
		hp(50), atk(5), dropItems{ "잡템", "목검", "천옷" }	// 멤버 초기화 리스트
	{ }
	unit(int _hp, int _atk, vector<string> _dropItems) :
		hp(_hp), atk(_atk), dropItems(_dropItems)	// 멤버 초기화 리스트
	{ }
	void PrintInfo()
	{
		cout << "hp: " << hp << '\n';
		cout << "atk: " << atk << '\n';
		cout << "dropItems: ";
		int size = dropItems.size();
		for (int i = 0; i < size; i++)
			cout << dropItems[i] << " ";
		cout << '\n';
	}
};

int main()
{
	cout << "monster\n";
	unit monster;
	monster.PrintInfo();

	cout << '\n' << "player\n";
	unit player(100, 10, { "골드" });
	player.PrintInfo();
}
monster
hp: 50
atk: 5
dropItems: 잡템 목검 천옷

player
hp: 100
atk: 10
dropItems: 골드

3번 초기화 리스트 사용처

  1. 상수 멤버 초기화
    • 상수는 선언할 때 반드시 초기화해야 한다.
    • 1번 방법도 가능하지만, 런타임 중 값을 1회에 한해 초기화해야 할 경우 꼭 3번 초기화 리스트를 사용해야 한다.
  2. 레퍼런스 멤버 초기화
    • 일종의 상수 포인터인 레퍼런스는 생성 직후부터 ‘별명’으로 동작해야 한다. 하여 초기화할 변수를 반드시 지정해야 한다.
    • 이땐 1번 방법보단 3번 방법으로 쓰일 것이다. 1번으로 할 시 레퍼런스가 참조하고 있는 멤버변수를 하나 더 정의해야 한다.
  3. 포함된 객체 초기화
    • 클래스가 다른 클래스의 객체를 멤버로 가질 때 사용


사용 예제

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

class coord
{
public:
	int x, y;
public:
	coord(int _x, int _y) : x(_x), y(_y) {}	// 객체 생성자
};

class unit
{
protected:
	coord position;	// 포함된 객체 멤버
	const int hp;	// 상수 멤버
	int& atk;	// 레퍼런스 멤버
public:
	unit(int x, int y, const int _hp, int& _atk) :
		position(x, y), hp(_hp), atk(_atk) {}	// position은 coord 객체의 생성자 포맷을 그대로 씀
	void PrintInfo()
	{
		cout << "position: { " << position.x << ", " << position.y << " }" << '\n';
		cout << "hp: " << hp << '\n';
		cout << "atk: " << atk << '\n';
	}
};

int main()
{
	cout << "monster\n";
	int atk = 10;
	unit monster(0, 0, 100, atk);
	monster.PrintInfo();
}
monster
position: { 0, 0 }
hp: 100
atk: 10

초기화 리스트를 사용하지 않을 경우 다음과 같은 오류를 띄운다.

image

또한 초기화 리스트의 장점은

객체의 모든 데이터 멤버가 초기화된다는 보장을 받는다.

이로써 실수로 초기화하지 않아 쓰레기값으로 초기화되는 미정의 동작을 방지한다.


초기화 우선순위

다음 코드를 통해 어떤 것이 나중에 초기화되는지 테스트해보자.

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

class unit
{
protected:
	int hp = printf("2. 멤버변수 hp 정의 시 \n");   // printf가 int를 반환하는 것을 이용
	int atk = printf("2. 멤버변수 atk 정의 시 \n");
public:
	unit() : hp(printf("3. 초기화 리스트 \n"))
	{
		hp = printf("1. 생성자 \n");
	}
};

int main()
{
	unit monster;
}
3. 초기화 리스트
2. 멤버변수 atk 정의 
1. 생성자

초기화 우선 순위가 다음과 같음을 알았다.

초기화 리스트 > 생성자

다만 hp와 atk를 비교해봄으로써

초기화 리스트로 멤버변수 정의 시 초기화가 호출이 안 되는 것도 확인했다.

멤버 초기화 리스트를 지우고 서열을 가려보자.

(생략)
unit() // : hp(printf("3. 초기화 리스트 \n"))
(생략)
2. 멤버변수 hp 정의 
2. 멤버변수 atk 정의 
1. 생성자

결론적으로

초기화 리스트 > (초기화 리스트에 없는)멤버 변수 정의 시 초기화 > 생성자에서 초기화

임을 알았다.

태그:

카테고리:

업데이트:

댓글남기기