2022. 11. 17. 17:10ㆍ개발공부/모두의 코드 C++
이글은 c++를 복습하기 위해 모두의 코드 https://modoocode.com/ 있는 강의 글을 보고 중요한 것들을 기록한 것입니다.
생성자의 초기화 리스트(initializer list)
기존의 생성자
Marine::Marine() {
hp = 50;
coord_x = coord_y = 0;
damage = 5;
is_dead = false;
}
생성자 초기화 리스트
Marine::Marine() : hp(50), coord_x(0), coord_y(0), damage(5), is_dead(false) {}
위 아래 둘다 하는 일이 똑같아 보이지만 차이가 있다. 무엇일까?
약간의 차이는 바로
왜냐하면, 초기화 리스트를 사용한 버전의 경우 생성과 초기화를 동시에 하는 것이고
반면에 초기화 리스트를 사용하지 않는다면 생성을 먼저 하고 그 다음에 대입 을 수행하는 것이다.
이해를 돕기 위한 두 코드
int a = 10
====================
int a;
a = 10;
전자의 경우 복사 생성자가 호출되는데, 후자의 경우 디폴트 생성자가 호출된 뒤 대입이 수행되는 것이다.
따라서 초기화 리스트를 사용하는 것이 조금 더 효율적이다. 또한, 레퍼런스와 상수처럼, '생성과 동시에 초기화되어야 하는 것들'이 있다.
상수와 레퍼런스는 생성과 동시에 초기화가 되어야 한다.
class Marine {
int hp; // 마린 체력
const int default_damage; // 기본 공격력
public:
Marine(); // 기본 생성자
};
Marine::Marine()
: hp(50), default_damage(5){}
따라서 만약에 클래스 내부에 레퍼런스 변수나 상수를 넣고 싶다면 이들을 생성자에서 무조건 초기화 리스트를 사용해서 초기화 시켜주어야만 한다.
생성자와 초기화 리스트의 차이를 좀더 알아보자면 접은 부분을 보세요
멤버 초기화 리스트의 일반적인 꼴
(생성자 이름) : var1(arg1), var2(arg2) {}
여기서 var 들은 클래스의 멤버 변수들을 지칭하고, arg 는 그 멤버 변수들을 무엇으로 초기화 할 지 지칭하는 역할
그래서 이런 형태도 가능하다
Marine::Marine(int coord_x, int coord_y)
: coord_x(coord_x), coord_y(coord_y), hp(50), damage(5), is_dead(false) {}
coord_x ( coord_x ) 에서 바깥쪽의 coord_x 는 무조건 멤버 변수를 지칭하게 되는데
,이 경우 coord_x 를 지칭하는 것이고, 괄호 안의 coord_x 는 원칙상 Marine 이 인자로 받은 coord_x 를
우선적으로 지칭하는 것이기 때문
반대로 생성자로
Marine::Marine(int coord_x, int coord_y) {
coord_x = coord_x;
coord_y = coord_y;
hp = 50;
damage = 5;
is_dead = false;
}
이경우는 에러가 난다.
why? 컴파일러가 두 coord_x 모두 인자로 받은 coord_x로 구분하기 때문
씹어먹는 모두의 코드를 보다보면 멤버변수를 아래 처럼 초기활 할 수없다고 나온다. 하지만
# c++ 11에서는 클래스의 일반 멤버 변수에 직접 기본 초기값을 할당할 수 있다. (즉, 초기화를 할 수 있다.)
#include <iostream>
class Rectangle
{
private:
double m_Length = 1.0; // or m_Length { 1.0 };
double m_Width = 1.0;
하지만 주의해야 할 점은 기본값이 지정되어 있더라도 생성자 멤버 초기화 리스트가 가장 우선시 된다는 것이다.
Static 변수
클래스 하나에만 종속되는 변수를 static 멤버 변수라고 한다. static 멤버 변수는 모든 객체들이 '공유'하는 변수이다.
예를 들어, 생성된 객체들의 갯수를 셀 때, static 멤버 변수를 활용하면 쉽게 구할 수 있다.
class Marine {
static int total_marine_num;
생성자
Marine::Marine()
: hp(50), coord_x(0), coord_y(0), default_damage(5), is_dead(false) {
total_marine_num++;
소멸자
~Marine() { total_marine_num--; }
}
이런식으로 생성 할 때 마다 static 변수를 증가시키면서 생성된 객체들의 수를 셀 수 있다.
모든 전역 및 static 변수들은 정의와 동시에 값이 자동으로 0 으로 초기화된다.
static int total_marine_num;
하지만 특정 값(여기선 100)으로 초기화 하고 싶다면
int Marine::total_marine_num = 100; 처럼 해야한다.
class Marine {
static int total_marine_num = 100; //틀린 코드이다. 실제로 작성해보면 오류로 뜬다.
Static 함수
특정 객체에 종속되는 것이 아닌 클래스 전체에 딱 1 개 존재하는 함수를 static 함수라고 한다.
static 변수밖에 다룰 수 없다. 일반 멤버 변수를 다루면 오류가 난다.
static 함수는 어떤 객체에 종속되는 것이 아니라 클래스에 종속되는 것으로, 따라서 이를 호출하는 방법도
(객체).(멤버 함수) 가 아니라,
Test::staticFunc();
와 같이 (클래스)::(static 함수) 형식으로 호출한다.
this 키워드
- this 포인터는 모든 멤버 함수에 추가되는 숨겨진 매개 변수다.
- 호출된 객체의 주소를 가리키는 상수 포인터다.
- 상수 포인터 자료형이므로 포인터 자체가 다른 것을 가리키도록 할 수는 없다.
this 키워드가 없는 함수는 static 함수뿐이다.
레퍼런스를 리턴하는 함수
c의 경우, 레퍼런스를 받았으므로, a의 x를 레퍼런스로 받은 것이다. 따라서 int& c = a.x; 와 같다. 따라서 a.x의 값이 4로 바뀐다.
반면 d의 경우, a.get_x()가 값을 리턴하므로, 이를 레퍼런스로 받을 수가 없다. 임시객체의 레퍼런스를 받을 수 없는 것이다.
e의 경우, e가 그냥 int 변수이므로, 값의 복사가 일어나 e에는 x의 값이 들어간다. 따라서, a.x의 값이 바뀌지 않는다.
우리는 이제 아래와 같은 코드를 제대로 이해할 수 있다.
Test& Test::ItSelfAsReference() {
return *this;
}
this는 객체를 가리키는 포인터이고, *this는 객체 자체이므로, 이를 레퍼런스로 넘겨 이후 해당 객체를 조작할 수 있도록 만드는 것이다.
상수 함수 (const 함수)
C++에서는 변수들의 값을 바꾸지 않고 읽기만 하는, 마치 상수 같은 멤버 함수를 상수 함수로 선언할 수 있다.
Test::Test get_a const { return this->a; }
const는 클래스 내부 멤버 변수들의 값을 바꾸지 않는다는 것을 보장한다.
'개발공부 > 모두의 코드 C++' 카테고리의 다른 글
C++ 기초개념 4-6 : explicit과 mutable 키워드 (0) | 2022.11.22 |
---|---|
C++ 기초개념 4-5 : 직접만들어보는 string (0) | 2022.11.18 |
C++ 기초개념 4-3 : 복사 생성자(깊은 복사,얕은 복사) , 소멸자 (0) | 2022.11.16 |
C++ 기초개념 4-2 : 함수의 오버로딩 , 생성자 ,디포트 생성자 (0) | 2022.11.16 |
C++ 기초개념 4-1 : 객체 (0) | 2022.11.16 |