본문 바로가기
개발/C, C++

C++ - explicit 키워드

by 피로물든딸기 2021. 8. 22.
반응형

C, C++ 전체 링크

 

아래의 코드를 실행해보자.

#include <stdio.h>
#include <iostream>

using namespace std;

class TEST
{
public:
	int value1;

	TEST()
		: value1(0)
	{
		cout << "생성자 호출" << endl;
	}

	TEST(int val1)
		: value1(val1)
	{
		value1 = val1;
		cout << "생성자 호출 2" << endl;
	}

	void printValue()
	{
		cout << value1 << endl;
	}
};

void implicitTypeCasting(TEST a)
{
	a.printValue();
}

int main(void)
{
	implicitTypeCasting(100);

	return 0;
}

 

TEST가 int에 대한 생성자를 제공하기 때문에 implicitTypeCasting 함수에서 묵시적 변환이 발생하였다.

TEST a가 생성자 호출 2를 출력되었으므로 아래의 코드가 실행되었다고 할 수 있다.

implicitTypeCasting(TEST(100));

 

의도적으로 묵시적 변환을 허용하지 않으려면 explicit 키워드를 사용하면 된다.

class TEST
{
public:
	int value1;

	...

	explicit TEST(int val1)
		: value1(val1)
	{
		value1 = val1;
		cout << "생성자 호출 2" << endl;
	}

	...
};

 

explicit으로 사용자가 묵시적으로 변환이 일어나게 하는 것을 컴파일 에러를 일으켜서 차단할 수 있다.

int main(void)
{
	// implicitTypeCasting(100); // compile error
	implicitTypeCasting(TEST(100)); // ok

	return 0;
}

위의 코드에 value2를 추가하고 main을 수정하여 testprintf로 출력해보자.

#include <stdio.h>
#include <iostream>

using namespace std;

class TEST
{
public:
	int value1;
	int value2;

	TEST()
		: value1(0), value2(0)
	{
		cout << "생성자 호출" << endl;
	}

	explicit TEST(int val1, int val2)
		: value1(val1), value2(val2)
	{
		value1 = val1;
		cout << "생성자 호출 2" << endl;
	}

	void printValue()
	{
		cout << value1 << value2 << endl;
	}
};

int main(void)
{
	TEST test = TEST(100, 200);

	printf("int  %d\n", test);
	printf("long %lld\n", test);

	return 0;
}

 

먼저 858993459300이 무엇을 의미하는지 알아보자.

계산기 - 프로그래머 모드를 이용하면 858993459300이 메모리에 어떻게 저장되는지 알 수 있다.

 

100은 아래와 같다.

 

200은 아래와 같다.

 

858993459300

00000000 00000000 00000000 11001000 00000000 00000000 00000000 01100100

= 200 과 100이 메모리에 저장된 상태를 long type으로 읽은 값이다.

 

printf의 %d는 변수가 뭐든 4바이트를 읽고, %lld는 8바이트를 읽기 때문에 위와 같은 값이 출력되었다.


이제 printf 대신 cout으로 test를 읽어보자.

int main(void)
{
	TEST test = TEST(100, 200);

	printf("int  %d\n", test);
	printf("long %lld\n", test);

	cout << test << endl;
	cout << (int)test << endl;

	return 0;
}

 

<< 연산자로 test를 읽을 방법이 없으니 compile 에러가 난다.

int로 강제로 형변환 하면 printf 처럼 읽을 수 있을 것 같지만, TEST는 int가 아니므로 형변환이 불가능하다.

 

그런데 c++에서는 이런 형변환 연산자도 오버로딩 할 수 있다.

여기서는 int로 강제 형변환 할 경우 value1, 2를 곱한 값을 return 하도록 하였다.

class TEST
{
public:
	int value1;
	int value2;

	...
    
	operator int() { return value1 * value2; }
};

 

cout을 통해 출력한 test와 (int)test가 100 x 200 = 20000으로 출력되는 것을 알 수 있다.

하지만 test도 20000이 출력되는 이유는 여기서도 묵시적 변환이 일어나기 때문이다.

 

다시 type casting int에 explicit을 명시해주면 묵시적 변환이 일어나지 않는다.

explicit operator int() { return value1 * value2; }

 

(int)test에 대한 에러는 사라졌고, 이전과 마찬가지로 << 연산자에 대한 compile error가 발생한다.

 

참고로 (int) test는 c 스타일의 강제 casting이므로 c++에서는 static_cast를 사용하는 것이 좋다.

static_cast는 컴파일 타임에서 가능한 형변환인지 체크한다.

#include <stdio.h>
#include <iostream>

using namespace std;

class TEST
{
public:
	int value1;
	int value2;

	TEST()
		: value1(0), value2(0)
	{
		cout << "생성자 호출" << endl;
	}

	explicit TEST(int val1, int val2)
		: value1(val1), value2(val2)
	{
		value1 = val1;
		cout << "생성자 호출 2" << endl;
	}

	void printValue()
	{
		cout << value1 << value2 << endl;
	}

	explicit operator int() { return value1 * value2; }
};

int main(void)
{
	TEST test = TEST(100, 200);

	printf("int  %d\n", test);
	printf("long %lld\n", test);

	//cout << test << endl;
	//cout << (int)test << endl; // c style
	cout << static_cast<int>(test) << endl;
	
	return 0;
}

반응형

댓글