안녕하세요. BlockDMask 입니다. 오늘은 C++11에서 추가된 non-static data member init이라는 주제에 대해서 이야기해보려합니다. '이 당연했던게 왜 C++11에 추가 되었지? 그전엔 왜없었지?'라는 생각이 들 정도로 편리(?)한 기능이라고 생각 하실수도 있습니다. 제 개인적인 생각으로는 이 기능이 꼭 좋기만할까? 휴먼 에러를 더 발생할 수 있지 않을까? 라는 생각이 들기도 합니다. 그럼 시작해보겠습니다.
<목차>
1. non-static data member init 이란?
1-1) C++11 이전에는?
1-2) C++11 이후에는?
2. 클래스 내부에서 초기화 하는것과 생성자에서 초기화 하는것의 순서에 대해서.
3. 비정적 멤버 변수 초기화에 대한 추가 지식과 개인적인 경험
1. non-static data member init 이란?
1-1) C++11 이전에 초기화
C++11이전에는 static data member만 클래스, 구조체 내부에서만 초기화가 가능했습니다. 한번 풀어서 이야기를 해보면, "정적 상수인 데이터 멤버만 클래스, 구조체 내부에서 초기화 될 수 있습니다." 여기서 "정적상수"란 간단히 이야기하면 static const 가 붙은 멤버를 말합니다.
이걸 반대로 생각해보면 "비정적 데이터 멤버들은 클래스, 구조체 내부에서 초기화가 불가능 하다." 는 것을 알 수 있습니다. 말로만 이야기 하니까 딱 오지 않으시죠? 코드를 보면 한번에 이해가 갈 것 입니다.
// C++11 이전
class Blog{
public:
static const int MAX_NUM = 10; // 정적 상수 초기화 가능
//int num1 = 10; // 비 정적 멤버 변수 초기화 불가능
//bool isEven = true; // 비 정적 멤버 변수 초기화 불가능
};
위 코드에서 보셨듯이 static const가 붙은 정적 상수만 초기화가 가능했었습니다. 일반 멤버 변수인 num1과 isEven은 선언하면서 바로 초기화 하는것이 불가능 했습니다. 그래서 우리는 비정적 멤버 변수들을 초기화 할때는 클래스의 생성자에서 초기화 해주거나 별도의 함수로 초기화 하곤 했었습니다. 아래와 같은 방법으로 말이죠.
- 생성자에서 초기화1
// C++11 이전 class Blog{ public: Blog(); int num1; // 비 정적 멤버 변수 초기화 불가능 bool isEven; // 비 정적 멤버 변수 초기화 불가능 }; // 생성자를 통한 멤버 변수 초기화 1 Blog::Blog() : num1(10), isEven(true) { // ... }
- 생성자에서 초기화2
// C++11 이전 class Blog{ public: Blog(); int num1; // 비 정적 멤버 변수 초기화 불가능 bool isEven; // 비 정적 멤버 변수 초기화 불가능 }; // 생성자를 통한 멤버 변수 초기화 2 Blog::Blog() { num1 = 20; isEven = false; }
- 초기화를 위한 멤버 함수에서 초기화
// C++11 이전 class Blog{ public: Blog(); // 생성자 void Init(); // 초기화 전용 함수 int num1; // 비 정적 멤버 변수 초기화 불가능 bool isEven; // 비 정적 멤버 변수 초기화 불가능 }; // 초기화 멤버 함수를 통한 멤버 변수 초기화 Blog::Blog() { Init(); } // 초기화 void Blog::Init() { num1 = 20; isEven = false; }
위 코드에서 보았듯이 생성자 혹은 다른 멤버 함수에서 클래스, 구조체의 멤버 변수를 초기화하는 방식으로 코드를 작성했었습니다. 그런데 C++11 이후 에서 부터는 선택지가 하나 더 생기게 되었습니다. 1-2)번으로 가볼가요? GOGO.
1-2) C++11 이후의 초기화
이제 C++11 에서 non-static data member init이라는것이 들어오면서 클래스 내부에서 변수 선언과 동시에 초기화가 가능해졌습니다. 즉, 정적 상수가 아닌 멤버 변수도 클래스, 구조체 내부에서 초기화가 바로 가능해졌다는 것 입니다.
바로 아래 코드를 보시죠.
// C++11 이후
class Blog{
public:
static const int MAX_NUM = 10; // 정적 상수 초기화 가능 (원래부터 가능)
int num2 = 20; // 비 정적 멤머 변수 초기화 가능
bool isOdd = true; // 비 정적 멤머 변수 초기화 매우 가능
};
이 얼마나 아름답고 깔끔해 보이는 코드인가요?
2. 클래스 내부에서 초기화 vs 생성자에서 초기화
자 이제 C++11 이후에서 멤버 변수를 초기화 할때 클래스, 구조체 내부에서도 초기화가 가능하다는 것도 알게 되었습니다.
그럼이제 뭘 알아야할까요? 기존 초기화는 그럼 필요가 없는가? 아니면 기존 초기화랑 초기화 순서는 어떨까? 이런 생각이 들지 않나요?
기존 초기화가 필요한지 안한지는 여러분들이 개발을 진행할때 '선택'에 달려있는것 같고
제가 알려드릴것은 기존 초기화랑 순서가 어떻게 되는지 만 알려 드리면 될 것 같습니다.
#include<iostream>
#include<string>
using namespace std;
class InitTest{
public:
InitTest(); // 생성자
void PrintAll();
private:
int num = 10;
double d = 0.55;
string str = "blockdmask";
};
// 생성자.
InitTest::InitTest()
: num(20), d(3.14), str("my blog")
{
// ...
}
// 출력을 위한 print 함수
void InitTest::PrintAll() {
cout << "num : " << num << endl;
cout << "d : " << d << endl;
cout << "str : " << str << endl;
}
// main 함수
int main(void)
{
InitTest* t1 = new InitTest();
t1->PrintAll();
delete(t1);
return 0;
}
이렇게 클래스 내부에서 비정적 멤버 변수를 초기화 하고 생성자에서도 다시 초기화 해주면 어떻게 될까요?
출력 결과
클래스 내부에서는 num = 10, d = 0.55, str = "blockdmask" 로 초기화를 했고, 그 뒤에 생성자에서 num = 20, d = 3.14, str = "my blog" 로 초기화 를 했습니다. 결과 값을 보면 생성자에서 초기화가 더 늦게 진행 되는 것을 볼 수 있습니다.
3. 비정적 멤버 변수 초기화에 대한 추가 지식과 개인적인 경험
: non-static data member init은 축약어로 NSDMI라 부릅니다.
: 클래스 내부에서 초기화를 진행하는것도 좋지만, 기존부터 생성자에서 초기화 해버릇 하시던 분은 그대로 생성자에서 진행해도 좋을것 같습니다. 저같은 경우에는 클래스 내부에서 초기화 하는 것을 배우자 마자 사용을 해봤는데 생성자에서 초기화를 해놓은걸 깜빡하고 두번 초기화 되어 디버깅 하는데 삽질한 경험이 있었습니다. 저와 같은 실수를 하지 않게 잘 선택하셔서 프로그램을 짜시면 좋을것 같습니다.
감사합니다. 오늘 포스팅은 여기 까지 입니다.
'<개인공부> > [C++]' 카테고리의 다른 글
[C++] 8진수, 10진수 16진수 출력 (입출력 형태 지정 1) (1) | 2021.02.04 |
---|---|
[C++] 표준 입출력 std::cin, std::cout 정리 및 예제 (0) | 2021.02.02 |
[C++] namespace 네임스페이스 정리 및 예제 (2) | 2021.02.01 |
[C++] override, final 키워드 (가상함수 관련 키워드)에 대해서 (0) | 2020.08.17 |
[C++] enum class (scoped enum) 에 대해서 (5) | 2020.07.30 |
[C++] auto 타입추론에 대해서 (3) | 2019.12.14 |
[C++] minmax() 최대값 최소값을 동시에 구하는 함수에 대해서 (0) | 2019.11.25 |
[C++] 최초값, 최대값 함수 min, max 에 대해서 (클래스, vector 사용법까지) (1) | 2019.11.22 |