본문 바로가기

Programming Languages/C++

[클래스와 객체]-생성자의 종류-디폴트 생성자

생성자는 어떠한 매개변수를 이용하여 객체를 초기화할 것인가에 따라 여러 개를 다중정의할 수 있다. 이러한 생성자 중에는 디폴트 생성자, 복사 생성자, 이동 생성자라는 특별한 유형의 생성자가 있다.

디폴트 생성자(default constructor)는 매개변수가 없는 생성자 또는 매개변수가 있지만 모두 디폴트 값이 있는 디폴트 인수만 포함하고 있는 생성자이다. 

ex) CounterM() { value = 0; }

위 예제의 생성자는 매개변수를 가지고 있지 않으므로 디폴트 생성자이다. 만일 클래스를 선언할 때 생성자를 선언하지 않으면 컴파일러는 아무런 일도 하지 않는 디폴트 생성자를 만든다. [소스코드 4-1]에 예시된 Counter 클래스는 생성자를 포함하고 있지 않으므로, 컴파일러는 다음과 같은 생성자를 자동적으로 제공한다.

class Counter {
 int value;
public:
 Counter() {} // 디폴트 생성자
 ......
}

그 결과 Counter 클래스의 객체를 생성하면 데이터 멤버가 초기화되지 않은 상태로 객체가 만들어진다.

그러나 생성자를 하나라도 선언하면 이와 같은 디폴트 생성자를 자동으로 만들지 않으며, 객체를 정의할 때에는 선언된 생성자에 맞는 형식으로 정의하여야만 한다. 예를 들어 [소스코드 4-6]의 클래스 CounterM은 

CounterM(int mVal) : maxValue{mVal}, value{0} {}

에서 1개의 매개변수를 갖는 생성자를 선언하였으므로 디폴트 생성자가 자동으로 만들어지지 않는다. 그러므로 CounterM 클래스의 객체를 정의할 때에는 반드시 다음의 ①과 같이 인수를 포함하여야 한다. ②와 같이 인수가 없는 형식으로 객체를 정의하는 것은 허용되지 않는다.

CounterM cnt1(999); // ① 0부터 999까지 카운트하는 계수기 객체 정의

CounterM cnt2;  // ② 에러 : CounterM은 디폴트 생성자가 없음

객체 배열

기본 자료형의 배열을 만드는 것과 마찬가지로 객체 배열도 만들 수 있다. 그러나 객체의 경우에는 생성자가 호출되어야 한다는 점을 염두에 두어야 한다. [소스코드 4-1]Counter 클래스의 경우 다음과 같이 객체 배열을 선언할 수 있다.

Counter cntArr[4]; // 4개의 객체로 구성되는 배열

이때 cntArr에 4개의 Counter 객체가 만들어지면서 각각의 객체마다 디폴트 생성자가 동작한다. 디폴트 생성자는 인수를 전달할 필요가 없기 때문에 이러한 형식으로 객체 배열을 선언하는 문장을 사용할 수 있다.

그러나 디폴트 생성자가 없는 클래스의 객체 배열은 이러한 형식으로 선언할 수 없다. 예를 들어 [소스코드 4-6]의 클래스 CounterM은 디폴트 생성자가 없으므로 다음과 같음 문장을 사용할 수 없다.

CounterM cntMArr[4]; // 에러 : 디폴트 생성자가 없어 생성자를 호출할 수 없음

CounterM의 생성자에는 계수기의 최댓값을 전달해야 하기 때문이다. 대신 다음과 같은 형식으로 배열을 선언할 수 있다. 

CounterM cntMArr[4] = { CounterM(9), CounterM(999) };

이 경우 최댓값이 각각 9, 999로 지정된 생성자에 의해 객체들이 초기화된다.

객채 배열을 new 연산자로 동적 할당을 할 때는 디폴트 생성자가 필요하다. 그렇지 않다면 초기화 인수를 전달할 수 없어 객체 배열을 동적 할당할 수 없다.

Counter *pt = new Counter[10]; // 10개의 객체로 구성된 배열을 동적 할당

CounterM *pte = new CounterM[10]; // 에러 : 디폴트 생성자가 없음