본문 바로가기
Programming/C++

[C++] 위임 생성자, 초기화 리스트 생성자

by 롱일스 2020. 8. 29.
반응형

▣ 생성자 처리 위임

 ●  위임 생성자(delegating constructor) 선언 

  ▷ C++11 이후에 생긴 생성자 

  ▷ 생성자 작성 코드의 중복을 줄이는 효과가 있다.

  ▷ 초기화 리스트에 앞에서 선언됐던 생성자를 사용해서 새로운 생성자를 선언하게 한다.

  •   위임 생성자: 앞에서 선언된 생성자를 이용하여 선언되는 생성자
  •   타겟 생성자: 위임의 대상이 되는 생성자

 

 ●  예시 - VecF 클래스

....
class VecF {
	int n;
	float *arr;
public:
	VecF(int d, float* a=nullptr) : n{ d } {
	arr = new float[d];
	if (a) memcpy(arr, a, sizeof(float) *n);
	}
    
    /*복사 생성자*/
	VecF(const VecF& fv) : n{ fv.n } {
	arr = new float[n];
	memcpy(arr, fv.arr, sizeof(float) *n);
	}
    .....
};

C++11 이전에는 생성자를 선언할 때 다른 생성자를 선언할 수 없었지만, C++11 이후부터는 앞서 정의된 생성자를 이용해서 새로이 생성자를 만들 수 있게 바꼈다.

....
class VecF {
	int n;
	float *arr;
public:
	VecF(int d, float* a=nullptr) : n{ d } {
	arr = new float[d];
	if (a) memcpy(arr, a, sizeof(float) *n);
	}
    
    /*복사 생성자*/
	VecF(const VecF& fv) : VecF(fv.n, fv.arr) {}
    .....
};

  ▷ VecF(const VecF& fv) : VecF(fv.n, fv.arr)에서 fv.ndl int고, fv.arr이 float*이므로 바로 위에 정의된 생성자가 호출된다. d에는 fv.n이, float* 매개변수에는 fv.arr이 들어가거 원래 정의됐던 생성자가 동작하게 한다.

  ▷ 불필요한 코드 중복을 줄였다.

 

▣ 초기화 리스트 생성자

 ●  초기화 리스트 생성자(initializer-list constructor)

  ▷ 첫 번째 매개변수가 std::initializer_list<Type>인 생성자다.

  ▷ 초기화 리스트를 매개변수로 받을 수 있도록 만든 생성자다.

  ▷ std::initializer_list<Type> 클래스란?

  •   지정된 자료형의 값들을 { } 안에 나열한 리스트
  •   헤더 파일은 #include <initializer_list> 로 설정한다.

 

멤버함수 용도
begin( ) 첫 번째 요소에 대한 포인터를 반환한다.
end( ) 마지막 요소의 다음 위치에 대한 포인터를 반환한다.
size( ) initialize_list의 원소 수를 반환한다.
  •  {1, 2, 3}에서 begin은 '1', end는 '3' 이 아닌 '3' 다음 위치를 가리킨다. 
  •  예시 -  initializer__list <int> list{1, 2, 3}; 일 때,  list.begin( ) = 1이 된다.

 

 ●  초기화 리스트 생성자 예시

class VecF {
    int n;
    float *arr;
public:
    VecF(int d, const float* a = nullptr) : n{ d } {
        arr = new float[d];
        if (a) memcpy(arr, a, sizeof(float) * n);
    }
    
    VecF(initializer_list<float> lst)
        : n{static_cast<int>(lst.size()) } {
        arr = new float[n];
        copy(lst.begin(), lst.end(), arr);
    }
    
};


int main()
{
    float a[4] = {1.0f, 2.0f, 3.0f, 4.0f};
    VecF v1(4,a);   // 배열의 개수도 매개변수로 받아야 했다.
    VecF v2(2.0f, 4.0f, 6.0f, 8.0f); //초기화 리스트 생성자
    
}
        

        

  ▷ n에 lst.size( )를 저장한다. 하지만 이 객체는 정수값이 아니기 때문에 에러가 나올 수 있다. 그래서 정수형으로 형변환하기 위해 static_cast<int>를 해준다. 

  ▷ n이 초기화 리스트로 초기화 된다.

  ▷ arr에 float값을 저장하기 위해 포인터에 new float[n]을 통해 n개의 데이터를 저장할 수 있는 float형 배열을 할당해준다.

  ▷ arr에 이 초기화 리스트에 들어 있는 값을 복사한다. 복사는 memcpy로 해도 되지만 copy()라는 함수를 써본다. 

  ▷ copy()에서 매개변수로 (1)맨 앞의 원소에 대한 포인터, (2)다음에 맨 뒤 원소 그 다음을 가리키는 포인터를 제시해주고 (3)그 다음에 복사 받을 배열/포인터를 지정해준다. --> initializer_list 데이터의 처음부터 끝까지 그대로 arr에 복사하게 된다.

  ▷ 객체를 만들 때 배열을 만들고 그것을 가지고 초기화해주는 생성자를 이용하지 않고, 초기화 리스트를 이용해서 직접 객체를 만드는 것이 가능해지므로 더 편리할 수 있다. 

728x90
반응형