들어가면서
클래스 생성자의 종류는 여러가지이다.
기본생성자부터 시작해 매개변수가 있는 생성자(이하 매개변수 생성자), 복사생성자, 이동생성자, 그리고 변환생성자가 존재한다.
변환생성자는 매개변수 생성자와 유사한 점이 있어서 혼동하기 쉬운 개념인데
이번 글에서 명확하게 구분하고 가자.
변환생성자란?
변환생성자는 단일 매개변수를 갖는 생성자로, 다른 타입의 값을 해당 클래스 타입으로 변환할 때 호출되는 생성자(멤버 함수)이다.
이해를 쉽게 하기 위해 아래 예제를 먼저 살펴보도록 하자.
int number = 10;
int 타입의 number는 대입연산자(=)에 의해 10을 변수 number에 할당하고 있는 모습이다.
이때, 대입연산자(=)는 오른쪽의 값을 왼쪽에 할당하는게 포인트이다.
그렇다면, 아래 예제에서 Tmp 클래스 타입에 대입연산자(=)를 사용해서 다음과 같이 할당한다면 어떻게 될까?
(Tmp 클래스 정의는 생략한다)
int main(void) {
Tmp t1 = 10; //error: no viable conversion from 'int' to 'Tmp'
return 0;
}
위 코드를 실행하면 error: no viable conversion from 'int' to 'Tmp' 가 발생한다.
즉, 오른쪽의 값인 int 타입의 10을 왼쪽 Tmp 클래스 타입에 할당할 수가 없고 적절히 변환시킬 수도 없게 된다.
보통은 클래스 타입의 객체 생성시 대입연산자(=)를 사용하지는 않지만, 만약 대입연산자를 사용한다면
적절하게 변환시킬 방법이 필요한데, 이때 '변환생성자'를 사용한다.
아래 코드를 같이 살펴보자.
#include <iostream>
using namespace std;
class Tmp{
private:
int number;
string name;
public:
Tmp();
Tmp(int num); //변환생성자 : int 타입을 Tmp 타입으로 변환시 자동으로 호출된다.
};
//변환생성자 정의
Tmp::Tmp(int num){
number = num;
cout << "My number is " << number << "." << endl;
}
//메인함수
int main(void) {
Tmp t1 = 10; //변환생성자에 의해 대입연산이 적절히 수행된다.
return 0;
}
Tmp 클래스 정의시 int타입의 단일 매개변수를 갖는 변환생성자를 선언하였다.
즉, main함수에서 대입연산에 의해 int타입의 값을 왼쪽에 할당할 때 컴파일 에러 없이 객체가 생성될 것이다.
변환생성자 정리
변환생성자는 매개변수 생성자와 유사하지만 다른 개념이며, 단일 매개변수를 가지고 대입연산시 다른 자료형을 적절히 변환시켜 객체를 생성시킨다.
이때, 주의할 점은 main함수에서 대입연산시 오른쪽 자료형이 변환생성자의 매개변수의 타입과 일치해야지 호출된다는 것이다.
즉, 위 예제에서는 변환생성자가 int 타입에 대해서만 정의가 되어있지만, 만약 대입 연산시 아래와 같이
int main(){
Tmp t1 = 3.141592;
return 0;
}
정의되어 있지 않는 double형 타입에 대해서는 변환생성자가 호출되지가 않는다.
.
.
.
또한, 변환생성자는 코드의 가독성을 떨어뜨리므로 보통은 잘 사용하지 않는다.
explicit 키워드
위에서 대입연산자(=)를 사용하여 다른 타입이 온다면 변환생성자가 호출된다고 이해하였다. 하지만, 이는 코드의 가독성을 떨어뜨리고 다른 사람이 보았을 때 오해의 소지가 발생할 수가 있다.
또한, 일반적으로 객체 생성시 대입연산자(=)를 사용하지 않고 괄호()나 중괄호{}를 사용하여 생성한다.
따라서, explicit 키워드를 사용하면, 대입연산자(=)를 통한 객체가 생성될 때 컴파일러가 에러를 발생시켜 이런 문제를 피할 수 있게 된다.
explicit 키워드는 변환생성자 앞에 사용되며, 아래 예제를 살펴보자.
#include <iostream>
using namespace std;
class Tmp{
private:
int number;
string name;
public:
Tmp();
explicit Tmp(int num);
};
Tmp::Tmp(int num){
number = num;
cout << "My number is " << number << "." << endl;
}
int main(void) {
Tmp t1 = 10; //no viable conversion from 'int' to 'Tmp'
return 0;
}
explicit 키워드를 사용하면, main함수에서 t1 객체를 대입연산자(=)를 통해 생성할 때 컴파일 에러가 발생된다.
에러가 발생된 코드를 적절히 수정해보면 다음과 같다.
int main(void) {
Tmp t1 {10};
return 0;
}
위와 같이 매개변수 생성자를 호출하는 것처럼 중괄호를 통해서만 초기화가 가능해진다.
따라서, explicit 키워드를 통해 가독성이 높아지고 코드의 안정성을 높일 수 있게 된다.
'C++' 카테고리의 다른 글
C++ : Cascaded Function Calls(멤버함수 체이닝, 연쇄호출)이란? (0) | 2024.03.20 |
---|---|
C++ : 클래스 내부의 this 포인터의 역할(this->멤버/(*this).멤버) (0) | 2024.03.20 |
C++ : friend 키워드란? (0) | 2024.03.18 |
C++ : cin >> int배열;은 왜 불가능 할까? (0) | 2024.03.15 |
C++ : 정적 멤버변수와 정적 멤버함수란? (Class심화) (0) | 2024.01.02 |