모든 객체는 생성 시 "생성자" 함수를 자동으로 호출한다.
컴파일러와 생성자
생성자는 반드시 생성 시에 호출되기 때문에, 사용자가 생성자를 별도로 선언하지 않아도 컴파일러가 아무 동작을 하지 않는 생성자를 자동으로 생성하여 추가한다. 다음 예시에서 볼 수 있듯이, 컴파일러가 자동 생성하는 생성자 덕분에 p1
선언에는 문제가 없지만 p2
선언은 컴파일 에러가 발생한다.
class Point
{
private:
int x;
int y;
};
int main(void)
{
Point p1;
Point p2(1, 2);
return 0;
}
test.cpp:11:8: error: no matching constructor for initialization of 'Point'
Point p2(1, 2);
^ ~~~~
test.cpp:1:7: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 2 were provided
class Point
^
test.cpp:1:7: note: candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 2 were provided
1 error generated.
에러 메세지를 좀 더 구체적으로 살펴보자.
아무 생성자가 제공되지 않았으나, 컴파일러는 2개의 생성자가 있음을 나타내고 있다.
- default constructor (디폴트 생성자) → 0개 argument
- copy constructor (복사 생성자) → 1개 argument
디폴트 생성자
여기서 디폴트 생성자가 바로 컴파일러가 자동으로 생성하는, 아무 동작을 하지 않는 일반 생성자이다.
Point::Point() { }
복사 생성자
그렇다면, 1개의 argument를 요구하는 복사 생성자는 무엇일까?
복사 생성자는 바로 생성자를 호출하는 객체와 동일한 타입의 객체를 인자로 전달받아, 전달받은 객체와 동일하게 객체를 구성(=복사)하는 생성자이다.
Point::Point(const Point& obj)
{
x = obj.x;
y = obj.y;
}
이렇게 복사 생성자가 자동으로 생성되기 때문에 다음과 같은 코드도 문제 없이 동작할 수 있다.
class Point
{
public:
Point(int x_val, int y_val) : x(x_val), y(y_val) { }
void print(std::string str)
{
std::cout << str << " : " << x << ", " << y << std::endl;
}
private:
int x;
int y;
};
int main(void)
{
Point p1(12, 34);
p1.print("p1");
Point p2(p1); // no error
p2.print("p2");
return 0;
}
p1 : 12, 34
p2 : 12, 34
실행 결과를 확인해보면 복사 생성자를 호출했을 p2
가 인자로 받은 p1
을 그대로 복사하였음을 볼 수 있다.
복사 생성자의 특징
- 별도의 복사 생성자가 제공되지 않으면 컴파일러가 자동으로 복사 생성자를 제공한다.
- 복사 생성자가 아닌 형태(= 동일 타입의 객체를 인자로 받는)의 일반 생성자가 제공되더라도 컴파일러는 제공된 복사 생성자가 없다면 자동으로 생성하여 복사 생성자를 제공한다.
- 별도의 복사 생성자가 제공된다면 컴파일러는 디폴트 생성자를 제공하지 않기 때문에 일반 생성자가 제공되어야 한다.
#include <iostream>
#include <string>
class Point
{
public:
Point(const Point &p) : x(p.x), y(p.y) { }
private:
int x;
int y;
};
int main(void)
{
Point p1; // error
}
test.cpp:15:8: error: no matching constructor for initialization of 'Point'
Point p1;
^
test.cpp:7:2: note: candidate constructor not viable: requires single argument 'p', but no arguments were provided
Point(const Point &p) : x(p.x), y(p.y) { }
^
1 error generated.
복사 생성자는 언제 호출될까?
- 복사 생성자는 어떤 객체에 대한 대입 및 초기화가 이뤄질 때 호출된다.
- 어떤 객체를 함수의 인자로 전달할 때 복사 생성자 호출을 통한 복사본이 생성된다.
- 함수가 객체를 리턴하게 될 때 리턴을 위한 임시 객체가 생성되므로 복사 생성자가 호출된다.
'C · C++' 카테고리의 다른 글
[C++] 템플릿 함수 오버로딩 (Template Function Overloading) (0) | 2023.07.02 |
---|---|
[C++] 템플릿(Template) 함수 (0) | 2022.07.27 |
[C++] 함수 오버로딩(Overloading) (0) | 2022.07.23 |
[C++] Default Arguments (Parameters) (0) | 2022.07.16 |
[C++] 함수의 선언과 구현부 분리 (0) | 2022.07.13 |