13.14 Converting constructors, explicit, and delete

주홍영·2022년 3월 18일
0

Learncpp.com

목록 보기
157/199

https://www.learncpp.com/cpp-tutorial/converting-constructors-explicit-and-delete/

#include <cassert>
#include <iostream>

class Fraction
{
private:
	int m_numerator;
	int m_denominator;

public:
	// Default constructor
	Fraction(int numerator = 0, int denominator = 1)
		 : m_numerator(numerator), m_denominator(denominator)
	{
		assert(denominator != 0);
	}

	// Copy constructor
	Fraction(const Fraction& copy)
		: m_numerator(copy.m_numerator), m_denominator(copy.m_denominator)
	{
		// no need to check for a denominator of 0 here since copy must already be a valid Fraction
		std::cout << "Copy constructor called\n"; // just to prove it works
	}

	friend std::ostream& operator<<(std::ostream& out, const Fraction& f1);
	int getNumerator() { return m_numerator; }
	void setNumerator(int numerator) { m_numerator = numerator; }
};

void printFraction(const Fraction& f)
{
	std::cout << f;
}

std::ostream& operator<<(std::ostream& out, const Fraction& f1)
{
	out << f1.m_numerator << "/" << f1.m_denominator;
	return out;
}

int main()
{
	printFraction(6);

	return 0;
}

위의 코드를 실행하면 출력은 의도한 대로 나온다

6/1

다만 printFraction은 파라미터로 Fraction 타입을 받아야 하는데
int 타입인 6을 전달해줬는데도 문제없이 실해이 되었다
왜냐하면 Fraction의 constructor가 single integer를 받아도 initialization을 할 수 있는 형태이므로 컴파일러가 implicitly convert를 진행했다

이러한 implicit conversion은 모든 타입의 initialization에서 통용된다

constructor에서 이러한 implicit conversion을 허용한 경우
우리는 converting constructors 라고 부른다

The explicit keyword

만약 이러한 implicit conversion을 허용하고 싶지 않다면 explicit keyword를 사용한다

#include <string>
#include <iostream>

class MyString
{
private:
	std::string m_string;
public:
	// explicit keyword makes this constructor ineligible for implicit conversions
	explicit MyString(int x) // allocate string of size x
	{
		m_string.resize(x);
	}

	MyString(const char* string) // allocate string to hold string value
	{
		m_string = string;
	}

	friend std::ostream& operator<<(std::ostream& out, const MyString& s);

};

std::ostream& operator<<(std::ostream& out, const MyString& s)
{
	out << s.m_string;
	return out;
}

void printString(const MyString& s)
{
	std::cout << s;
}

int main()
{
	MyString mine = 'x'; // compile error, since MyString(int) is now explicit and nothing will match this
	std::cout << mine;

	printString('x'); // compile error, since MyString(int) can't be used for implicit conversions

	return 0;
}

위와 같이 explicit 키워드를 constructor에 사용하면 implicit conversion이 일어나는 것을 방지한다

The delete keyword

앞서 explicit로 implicit conversion을 방지했다
이번에는 delete 키워드를 이용해서 특정 타입을 파라미터로 받는 constructor를 아예 사용 불가능으로 만들 수도 있다

#include <string>
#include <iostream>

class MyString
{
private:
	std::string m_string;

public:
	MyString(char) = delete; // any use of this constructor is an error

	// explicit keyword makes this constructor ineligible for implicit conversions
	explicit MyString(int x) // allocate string of size x /
	{
		m_string.resize(x);
	}

	MyString(const char* string) // allocate string to hold string value
	{
		m_string = string;
	}

	friend std::ostream& operator<<(std::ostream& out, const MyString& s);

};

std::ostream& operator<<(std::ostream& out, const MyString& s)
{
	out << s.m_string;
	return out;
}

int main()
{
	MyString mine('x'); // compile error, since MyString(char) is deleted
	std::cout << mine;
	return 0;
}

위와 같이 MyString(char) = delete;라고 설정하면
main 함수에서 Mystring mine('x'); 로 initialization을 하려고 하는 경우 compile error가 발생한다

profile
청룡동거주민

0개의 댓글