728x90
다양한 초기화 방법
C++ 에서는 =,(),{} 와 같은 다양한 초기 방법이 있다.
(일반 자료형과 객체 타입 초기화 방식에는 약간의 차이가 있다.)
장점
- 축소 변환 방지(컴파일 에러)
- 배열의 초기화 문법 {}와 같이 생성자를 정의할 수 있다.
단점
- initializer_list<T> 생성자를 이용하여 stl container vector와 같은 방식으로 초기화 할 수 있다. 이때 일반적인 생성자 시그니처와 initailizer 초기화 방식의 시그니처가 동일한 경우 (), {}에 따라 다른 생성자가 호출된다. 이는 초기화 호출방식에 대한 혼란을 야기시킨다.
결론
- 소괄호 초기화
- 전통적인 초기화 방식 → 거부가 없음
- vector 등 특이한 케이스에 대해서면 {} 사용
- 중괄호 초기화 {}
- 초기화 문법 일치화(intializer_list<T> 생성자를 이용) ⇒ 100% 대응하진 못함.
- 축소 변환 방지
- 개인 생각
- 중괄호 초기화 방식의 축소변환은 확실히 개발단계에서 장점이지만 이고 개인의 취향에 따른 선택사항이지만 중괄호 초기화로 인해 생성자 호출 방식에 있어서 분기점이 생긴다. 이는 팀단위 개발에서는 코드 가독성을 떨어뜨릴 것 같다. {}초기화는 약속된 특정 클래스에서만 합의하에 사용하는게 좋을 것 같다. 애초에 ms도 그렇게 사용하는 것(?) 같다.
#include <iostream>
#include <vector>
using namespace std;
class Knight
{
public:
Knight()
{
cout << "Knight 기본 생성자" << endl;
}
Knight(const Knight& k)
{
cout << "Knight 복사 생성자" << endl;
}
Knight& operator = (const Knight& k)
{
cout << "Knight 대입 연산자" << endl;
hp = k.hp;
return *this;
}
public:
int hp = 100;
};
class Mage
{
public:
Mage()
{
}
Mage(int a, int b)
{
cout << "Mage(int int)" << endl;
}
Mage(initializer_list<int> li)
{
cout << "Mage(initailizer_list)" << endl;
}
};
Knight Func()
{
return Knight();
}
int main()
{
// 다양한 초기 방법
{
// 일반 자료형
int a = 0;
int b(0);
int c = (0);
int d{ 0 };
int e = { 0 };
// 객체 타입
Knight k1; // k1 기본 생성자
Knight k2 = k1; // k2 복사 생성자
Knight k3; // k3 기본 생성자
k3 = k1; // k3 대입 연산자
Knight k4{ k2 }; // k4 복사 생성자.
}
// !주의!
{
Knight k5(); // knight k5; 이 기본생성자를 호출하는 거고 knight k5()는 함수 선언문이다. void형 매개변수에 리턴값이 knight인 k5.
Knight k6{}; // 이건 기본생성자 버전.
}
// {} 초기화 장점 - 축소 변환 방지
{
// 일반 초기화시 축소됨
double x = 1.34;
int y = x; // 컴파일에서 경고
int z = { x }; // 컴파일에서 에러
}
// {} 초기화 장점 - 배열과 같은 방식을 객체 초기화 가능.
{
// 번거로운 초기화 방식
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
// {}를 이용한 초기화 방식. 마치 배열 초기화 방식과 유사
int arr[] = { 1,2,3,4,5 };
v1 = { 1,2,3,4 };
}
// {} 문제점 - 아래 두 초기화 방식은 다른 생성자를 호출한다. - why?
{
vector<int> v1{10 , 1}; // 벡터 크기를 10으로 지정하고 모든 요소를 1로 초기하는 생성자 호출.
vector<int> v2(10, 1); // 벡터에 10, 1 두 값을 초기화하는 생성자 initalizer_list 생성자 호출.
}
// {} 문제점 재현
{
Mage m{ 3,4 }; // initailizer 생성자가 정의되어 있으면 Mage(int a, int b) 생성자는 호출되지 않습니다.
}
return 0;
}
공부한 내용을 개인적으로 복습하기 쉬운 형태로 정리했습니다.
잘못된 내용이 있는 경우 언제든 댓글 혹은 이메일로 지적해주시면 감사드립니다.
728x90
'Programming Language > C++' 카테고리의 다른 글
std::function (0) | 2022.02.10 |
---|---|
Modern C++/lambda/람다 (0) | 2022.02.09 |
using - type alias declaration (0) | 2022.02.06 |
auto (0) | 2022.02.06 |
함수 객체(함수자, Functor) (0) | 2022.02.06 |