기본 생성자

"오늘의AI위키"는 AI 기술로 일관성 있고 체계적인 최신 지식을 제공하는 혁신 플랫폼입니다.
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.

1. 개요

기본 생성자는 C++, Java, C# 등 프로그래밍 언어에서 클래스의 객체를 초기화하는 데 사용되는 특수한 생성자이다. C++에서는 인자 없이 호출될 수 있는 생성자를 기본 생성자로 정의하며, 컴파일러가 명시적으로 정의된 생성자가 없을 경우 암묵적으로 생성한다. C++11부터는 `= default`와 `= delete`를 사용하여 기본 생성자의 생성을 제어할 수 있다. Java와 C#에서는 클래스에 생성자가 정의되지 않은 경우 컴파일러가 자동으로 생성하는 무인자 생성자를 기본 생성자라고 한다.

기본 생성자
📚 더 읽어볼만한 페이지
  • 메소드 (컴퓨터 프로그래밍) - 소멸자 (컴퓨터 프로그래밍)
    소멸자는 객체가 메모리에서 제거되기 직전에 호출되는 멤버 함수로, 객체 자원 해제 및 정리 작업을 수행하며, C++ 등 여러 언어에서 구현되고 메모리 누수 방지에 기여한다.
  • 메소드 (컴퓨터 프로그래밍) - 동적 디스패치
    동적 디스패치는 프로그램 실행 시 호출할 메서드를 결정하는 메커니즘으로, 단일 또는 다중 객체 기준으로 선택하며, 유연성과 확장성을 높이지만 성능 오버헤드를 발생시킬 수 있다.
  • 프로그래밍 구성체 - 형 변환
    형 변환은 프로그래밍에서 변수의 데이터 타입을 변경하는 것으로, 암시적 형 변환과 명시적 형 변환으로 나뉘며, 객체 지향 프로그래밍에서는 업캐스팅과 다운캐스팅이 발생하고, 각 언어는 고유한 규칙과 방법을 제공하며 잘못된 형 변환은 오류를 유발할 수 있다.
  • 프로그래밍 구성체 - 연산자 오버로딩
    연산자 오버로딩은 프로그래밍 언어에서 기존 연산자를 사용자 정의 자료형에 대해 재정의하여 내장 자료형처럼 다루도록 하는 기능으로, 코드 가독성과 표현력을 높이지만 남용 시 코드 의미를 모호하게 만들 수 있다.
  • 제어 흐름 - 프로그램 카운터
    프로그램 카운터는 CPU 내에서 다음에 실행될 명령어의 주소를 저장하는 레지스터로, 명령어 사이클의 fetch 단계에서 사용되어 명령어를 가져오고 실행 후 갱신되며, CPU 성능 향상 기술과 현대 프로그래밍 모델에 영향을 미친다.
  • 제어 흐름 - 예외 처리
    예외 처리는 프로그램 실행 중 예외 발생 시 정상적인 실행 흐름을 유지하거나 안전하게 종료하기 위한 메커니즘으로, 많은 프로그래밍 언어에서 제공하며 예외 안전성을 목표로 한다.

2. C++

C++컴파일러는 클래스에 명시적으로 정의된 생성자가 없을 때 기본 생성자를 암묵적으로 선언하고 정의한다. 이 암묵적으로 정의된 기본 생성자는 빈 바디와 함께 명시적으로 정의된 것과 동일하다. 만약 클래스에 명시적으로 정의된 생성자가 있지만, 모두 기본 생성자가 아니라면, 컴파일러는 암시적으로 기본 생성자를 정의하지 않는다. 이는 클래스가 기본 생성자를 갖지 않는 상황으로 이어진다.

C++에서 기본 생성자는 다음과 같은 특정 상황에서 자동적으로 작동되므로 중요하다.

* 객체 값이 인자 목록 없이 정의되거나(`MyClass x;`) 인자 목록 없이 동적으로 할당될 때 (`new MyClass;` 또는 `new MyClass();`)
* 객체들의 배열이 정의되거나(`MyClass x[10];`) 동적으로 할당될 때 (`new MyClass [10]`)
* 상속하는 클래스 생성자가 자신의 초기화 리스트에서 명시적으로 베이스 클래스 생성자를 호출하지 않을 때
* 클래스 생성자가 자신의 초기화 리스트에서 객체 값을 갖는 것 중 하나의 생성자를 명시적으로 호출하지 않을 때
* 표준 라이브러리에서, 값이 명시적으로 주어지지 않았을 때 특정한 컨테이너가 기본 생성자를 사용해서 값을 채울 때

프로그래머와 컴파일러 모두 기본 생성자를 정의하지 않으면, 객체 생성 시 오류가 발생한다.

C++11에서는 `= default`를 사용하여 기본 생성자를 명시적으로 생성하거나, `= delete`를 사용하여 명시적으로 금지할 수 있다.

2.1. 기본 생성자의 정의와 호출

C++ 표준에서는 인자 없이 호출할 수 있는 생성자를 기본 생성자로 정의한다. 여기에는 모든 매개변수에 기본값이 있는 생성자도 포함된다.

예를 들면 다음과 같다.

```cpp
class MyClass
{
public:
MyClass(); // 생성자 선언

private:
int x;
};

MyClass::MyClass() : x(100) // 생성자 정의
{
}

int main()
{
MyClass m; // 런타임에 객체 m이 생성되고 기본 생성자가 호출됨
}
```

위의 코드에서 `MyClass()`는 인자가 없는 기본 생성자이다.

메모리를 동적으로 할당할 때, 클래스 이름 뒤에 괄호를 추가하여 기본 생성자를 명시적으로 호출할 수 있다.

```cpp
int main()
{
MyClass * pointer = new MyClass(); // 런타임에 객체가 생성되고 기본 생성자가 호출됨
}
```

생성자에 하나 이상의 매개변수가 있지만, 모두 기본값을 가지는 경우도 기본 생성자에 해당한다.

```cpp
class MyClass
{
public:
MyClass (int i = 0, std::string s = ""); // 생성자 선언

private:
int x;
int y;
std::string z;
};

MyClass::MyClass(int i, std::string s) // 생성자 정의
{
x = 100;
y = i;
z = s;
}
```

위의 코드에서 `MyClass (int i = 0, std::string s = "")`는 모든 매개변수가 기본값을 가지므로 기본 생성자이다.

2.2. 기본 생성자의 중요성

C++에서 기본 생성자는 특정 상황에서 자동으로 호출되기 때문에 중요하다. 이러한 상황에서 클래스에 기본 생성자가 없으면 오류가 발생한다. 기본 생성자가 필요한 경우는 다음과 같다.

* 객체가 인자 없이 정의되거나(예: `MyClass x;`) 인자 없이 동적으로 할당될 때 (예: `new MyClass;` 또는 `new MyClass();`), `MyClass`의 기본 생성자가 객체를 초기화하는 데 사용된다.
* 객체 배열이 정의될 때 (예: `MyClass x[10];`) 또는 동적으로 할당될 때 (예: `new MyClass [10]`), `MyClass`의 기본 생성자가 모든 요소를 초기화하는 데 사용된다.
* 상속하는 클래스 생성자가 자신의 초기화 리스트에서 명시적으로 베이스 클래스 생성자를 호출하지 않으면, 베이스 클래스의 기본 생성자가 호출된다.
* 클래스 생성자가 자신의 초기화 리스트에서 객체 값을 갖는 필드 중 하나의 생성자를 명시적으로 호출하지 않으면, 해당 필드 클래스의 기본 생성자가 호출된다.
* 표준 라이브러리에서 특정 컨테이너는 명시적으로 값이 주어지지 않은 경우 기본 생성자를 사용하여 값을 채운다. (예: `vector(10);`는 기본 생성자로 생성된 `MyClass` 객체 10개로 벡터를 초기화한다.)

클래스에 명시적으로 정의된 생성자가 없다면, 컴파일러는 기본 생성자를 암묵적으로 선언하고 정의한다. 이 암묵적으로 정의된 기본 생성자는 빈 몸체와 함께 명시적으로 정의된 것과 동일하다.

클래스에 명시적으로 정의된 생성자가 있지만, 모두 기본 생성자가 아니라면, 컴파일러는 암시적으로 기본 생성자를 정의하지 않는다. 이는 클래스가 기본 생성자를 갖지 않는 상황으로 이어져 오류를 발생시킨다.

2.3. 컴파일러에 의한 기본 생성자 자동 생성

C++에서 클래스에 명시적으로 정의된 생성자가 없는 경우, 컴파일러는 자동으로 기본 생성자를 생성한다. 이 암묵적으로 정의된 기본 생성자는 빈 몸체(body)를 가진 명시적으로 정의된 생성자와 동일하다.

```cpp
class MyClass
{
int x; // 생성자가 없으므로 컴파일러는 (암시적) 기본 생성자를 생성합니다.
};

int main()
{
MyClass m; // 런타임 오류 없음: (암시적) 기본 생성자가 호출됩니다.
}
```

반면, 클래스에 명시적으로 정의된 생성자가 있지만 모두 기본 생성자가 아닌 경우, 컴파일러는 암시적으로 기본 생성자를 정의하지 않는다. 이는 클래스에 기본 생성자가 없는 상황을 초래하며, 흔히 오류로 이어진다.

```cpp
class MyClass
{
public:
MyClass (int y); // 비-기본 생성자 선언
private:
int x;
};

MyClass::MyClass (int y)
{
x = y;
}

int main()
{
MyClass m(100); // 비-기본 생성자가 호출됩니다.
MyClass * p; // 포인터 선언의 경우, 컴파일러는 생성자에 대해 알 필요가 없습니다.
p = new MyClass(); // 컴파일 시 오류: 기본 생성자 없음.
return 0;
}

2.4. C++11에서의 기본 생성자 제어

C++11에서는 `= default`를 사용하여 기본 생성자를 명시적으로 생성할 수 있다.

```cpp
class MyClass
{
public:
MyClass() = default; // 기본 생성자 생성을 강제합니다.
};
```

`= delete`를 사용하여 기본 생성자 생성을 명시적으로 금지할 수도 있다.

```cpp
class MyClass
{
public:
MyClass() = delete; // 기본 생성자 생성을 방지합니다.
};

3. Java 및 C#

자바와 C#에서 기본 생성자는 클래스에 생성자가 정의되지 않은 경우 컴파일러가 자동으로 생성하는 무인자 생성자이다.

3.1. Java 및 C# 기본 생성자의 특징

자바와 C# 모두에서 "기본 생성자"는 클래스에 대해 생성자가 정의되지 않은 경우 컴파일러가 자동으로 생성하는 무인자 생성자를 의미한다. 기본 생성자는 암묵적으로 상위 클래스의 무인자 생성자를 호출한 다음 빈 본문을 실행한다. 모든 필드는 초기값인 0(정수형), 0.0(부동 소수점형), `false` (boolean형) 또는 `null` (참조형)로 남겨둔다. 매개변수가 없는 프로그래머가 정의한 생성자도 C#에서는 기본 생성자라고 부르지만, 자바에서는 그렇지 않다.