초기화 목록은 클래스의 데이터 멤버를 초기화하는 데 사용됩니다. 초기화할 멤버 목록은 생성자를 사용하여 쉼표로 구분된 목록과 콜론으로 표시됩니다. 다음은 초기화 목록을 사용하여 Point 클래스의 x와 y를 초기화하는 예입니다.
예
C++
#include> using> namespace> std;> class> Point {> private>:> >int> x;> >int> y;> public>:> >Point(>int> i = 0,>int> j = 0): x(i), y(j) {}> >/* The above use of Initializer list is optional as the> >constructor can also be written as:> >Point(int i = 0, int j = 0) {> >x = i;> >y = j;> >}> >*/> >int> getX()>const> {>return> x; }> >int> getY()>const> {>return> y; }> };> int> main()> {> >Point t1(10, 15);> >cout <<>'x = '> << t1.getX() <<>', '>;> >cout <<>'y = '> << t1.getY();> >return> 0;> }> |
>
>산출
x = 10, y = 15>
위의 코드는 초기화 목록의 구문에 대한 예일 뿐입니다. 위 코드에서 x와 y는 생성자 내에서 쉽게 초기화될 수도 있습니다. 그러나 생성자 내부의 데이터 멤버 초기화가 작동하지 않고 초기화 목록을 사용해야 하는 상황이 있습니다. 그러한 경우는 다음과 같습니다.
1. 비정적 const 데이터 멤버 초기화의 경우
const 데이터 멤버는 초기화 목록을 사용하여 초기화되어야 합니다. 다음 예제에서 t는 Test 클래스의 const 데이터 멤버이며 초기화 목록을 사용하여 초기화됩니다. 이니셜라이저 목록에서 const 데이터 멤버를 초기화하는 이유는 const 데이터 멤버에 대해 별도로 할당된 메모리가 없기 때문입니다. 심볼 테이블에 접혀 있으므로 이니셜라이저 목록에서 초기화해야 합니다.
또한 이는 매개변수화된 생성자이므로 할당 연산자를 호출할 필요가 없습니다. 이는 하나의 추가 작업을 피한다는 의미입니다.
예
C++
// C++ progmram to demonstrate the use of> // initializer list to initialize the const> // data member> #include> using> namespace> std;> class> Test {> >const> int> t;> public>:> >//Initializer list must be used> >Test(>int> t):t(t) {}> >int> getT() {>return> t; }> };> int> main() {> >Test t1(10);> >cout< return 0; }> |
>
>산출
10>
2. 참조멤버 초기화를 위해
참조 멤버는 초기화 목록을 사용하여 초기화되어야 합니다. 다음 예제에서 t는 Test 클래스의 참조 멤버이며 초기화 목록을 사용하여 초기화됩니다.
예
C++
자바 예외
// Initialization of reference data members> #include> using> namespace> std;> class> Test {> >int> &t;> public>:> >Test(>int> &t):t(t) {}>//Initializer list must be used> >int> getT() {>return> t; }> };> int> main() {> >int> x = 20;> >Test t1(x);> >cout< x = 30; cout< return 0; }> |
>
>산출
20 30>
3. 기본 생성자가 없는 멤버 개체를 초기화하는 경우
다음 예제에서 A 클래스의 객체 a는 B 클래스의 데이터 멤버이고 A에는 기본 생성자가 없습니다. 초기화하려면 초기화 목록을 사용해야 합니다.
예
C++
// C++ progmam to initialize a member object without default> // constructor> #include> using> namespace> std;> class> A {> >int> i;> public>:> >A(>int>);> };> A::A(>int> arg)> {> >i = arg;> >cout <<>'A's Constructor called: Value of i: '> << i> ><< endl;> }> // Class B contains object of A> class> B {> >A a;> public>:> >B(>int>);> };> B::B(>int> x) : a(x)> {>// Initializer list must be used> >cout <<>'B's Constructor called'>;> }> int> main()> {> >B obj(10);> >return> 0;> }> |
>
>산출
A's Constructor called: Value of i: 10 B's Constructor called>
클래스 A에 기본 생성자와 매개변수화된 생성자가 모두 있는 경우 기본 생성자를 사용하여 초기화하려는 경우 초기화 목록은 필수가 아니지만 매개변수화된 생성자를 사용하여 초기화하려면 필수입니다.
4. 기본 클래스 멤버 초기화의 경우
3번 항목과 마찬가지로 기본 클래스의 매개변수화된 생성자는 초기화 목록을 통해서만 호출할 수 있습니다.
예
C++
#include> using> namespace> std;> class> A {> >int> i;> public>:> >A(>int> );> };> A::A(>int> arg) {> >i = arg;> >cout <<>'A's Constructor called: Value of i: '> << i << endl;> }> // Class B is derived from A> class> B: A {> public>:> >B(>int> );> };> B::B(>int> x):A(x) {>//Initializer list must be used> >cout <<>'B's Constructor called'>;> }> int> main() {> >B obj(10);> >return> 0;> }> |
>
>산출
A's Constructor called: Value of i: 10 B's Constructor called>
5. 생성자의 매개변수 이름이 데이터 멤버와 동일한 경우
생성자의 매개변수 이름이 데이터 멤버 이름과 동일한 경우 데이터 멤버는 다음 중 하나를 사용하여 초기화해야 합니다. 이 포인터 또는 초기화 목록. 다음 예에서 A()의 멤버 이름과 매개변수 이름은 모두 i입니다.
예
C++
#include> using> namespace> std;> class> A {> >int> i;> public>:> >A(>int>);> >int> getI()>const> {>return> i; }> };> A::A(>int> i) : i(i)> {> }>// Either Initializer list or this pointer must be used> /* The above constructor can also be written as> A::A(int i) {> >this->나는 = 나;> }> */> int> main()> {> >A a(10);> >cout << a.getI();> >return> 0;> }> |
>
>산출
10>
6. 성능상의 이유로
몸체 내부에 값을 할당하는 것보다 초기화 목록의 모든 클래스 변수를 초기화하는 것이 좋습니다. 다음 예를 고려하십시오.
예
C++
자바 우선순위 큐
// Without Initializer List> class> MyClass {> >Type variable;> public>:> >MyClass(Type a) {>// Assume that Type is an already> >// declared class and it has appropriate> >// constructors and operators> >variable = a;> >}> };> |
>
>
여기서 컴파일러는 다음 단계에 따라 MyClass 유형의 객체를 생성합니다.
1. 유형의 생성자가 먼저 호출됩니다.
2. 기본 구성 변수
3. Type의 할당 연산자는 MyClass() 생성자의 본문 내부에서 호출되어 할당됩니다.
variable = a;>
4. 그리고 마지막으로 Type의 소멸자가 범위를 벗어나므로 a가 호출됩니다.
이제 초기화 목록이 있는 MyClass() 생성자와 동일한 코드를 고려해 보세요.
C++
// With Initializer List> class> MyClass {> >Type variable;> public>:> >MyClass(Type a):variable(a) {>// Assume that Type is an already> >// declared class and it has appropriate> >// constructors and operators> >}> };> |
>
>
초기화 목록을 사용하면 컴파일러가 다음 단계를 따릅니다.
1. 유형의 생성자가 먼저 호출됩니다.
2. Type 클래스의 매개변수화된 생성자가 변수(a)를 초기화하기 위해 호출됩니다. 이니셜라이저 목록의 인수는 생성 변수를 직접 복사하는 데 사용됩니다.
3. Type의 소멸자는 범위를 벗어나므로 a를 호출합니다.
이 예제에서 볼 수 있듯이 생성자 본문 내에서 할당을 사용하면 생성자 + 소멸자 + 하나의 추가 할당 연산자 호출이라는 세 가지 함수 호출이 있습니다. 그리고 초기화 목록을 사용하면 복사 생성자 + 소멸자 호출이라는 두 가지 함수 호출만 있습니다. 이 점에 대한 실행 예제는 이 게시물을 참조하세요.
이러한 할당 페널티는 그러한 변수가 많은 실제 응용 프로그램에서 훨씬 더 커질 것입니다. 덕분에 ptr 이 점을 추가하기 위해.
C++의 매개변수와 균일 초기화
변환 범위 축소 및 예상치 못한 동작 문제를 방지하려면 매개변수 초기화()보다는 균일한 초기화 {}가 포함된 초기화 목록을 사용하는 것이 더 좋습니다. 초기화 중에 더 엄격한 유형 검사를 제공하고 잠재적인 축소 변환을 방지합니다.
매개변수 초기화를 사용하는 코드()
C++
#include> class> Base {> >char> x;> public>:> >Base(>char> a)> >: x{ a }> >{> >}> >void> print() { std::cout <<>static_cast><>int>>(엑스); }> };> int> main()> {> >Base b{ 300 };>// Using uniform initialization with {}> >b.print();> >return> 0;> }> |
>
>산출
44>
위 코드에서 값 300은 char의 유효한 범위를 벗어났습니다. 이로 인해 정의되지 않은 동작이 발생하고 잠재적으로 잘못된 결과가 발생할 수 있습니다. 컴파일러는 컴파일 설정에 따라 이 상황에 대한 경고나 오류를 생성할 수 있습니다.
균일한 초기화 {}를 사용하는 코드
{}로 균일한 초기화를 사용하고 제공된 값 a로 x를 초기화함으로써 컴파일러는 더 엄격한 유형 검사를 수행하고 컴파일 중에 경고 또는 오류를 발행하여 int에서 char로의 변환 범위를 좁히는 것을 나타냅니다.
다음은 균일한 초기화 {}를 사용하는 코드입니다. 이로 인해 경고가 발생하므로 사용하는 것이 더 좋습니다.
C++
#include> class> Base {> >char> x;> public>:> >Base(>char> a)> >: x{ a }> >{> >}> >void> print() { std::cout <<>static_cast><>int>>(엑스); }> };> int> main()> {> >Base b{ 300 };>// Using uniform initialization with {}> >b.print();> >return> 0;> }> |
>
>
main.cpp: In function ‘int main()’: main.cpp:17:17: error: narrowing conversion of ‘300’ from ‘int’ to ‘char’ [-Wnarrowing] 17 | Base b{ 300 }; // Using uniform initialization with {} | ^>