18.11 Printing inherited classes using operator<<

주홍영·2022년 3월 21일
0

Learncpp.com

목록 보기
182/199

https://www.learncpp.com/cpp-tutorial/printing-inherited-classes-using-operator/

virtual function을 사용하는 다음 프로그램을 살펴보자

#include <iostream>

class Base
{
public:
	virtual void print() const { std::cout << "Base";  }
};

class Derived : public Base
{
public:
	void print() const override { std::cout << "Derived"; }
};

int main()
{
	Derived d{};
	Base& b{ d };
	b.print(); // will call Derived::print()

	return 0;
}

이제 우리는 b.print가 Derived::print()를 호출하는 것에 대해서 이해하고 있다

우리가 이를 std::cout과 연계를 하고 싶은데 현재 형태에서는 깔끔하게 이를 사용할 수 없다

#include <iostream>

int main()
{
	Derived d{};
	Base& b{ d };

	std::cout << "b is a ";
	b.print(); // messy, we have to break our print statement to call this function
	std::cout << '\n';

	return 0;
}

b.print()가 std::cout이 존재하므로 위처럼 써야한다

이상적으로는 다음과 같이 쓴는게 깔끔해보인다

std::cout << "b is a " << b << '\n'; // much better

The challenges with operator<<

operator<<에 일반적인 방법으로 overloading을 해보자

#include <iostream>

class Base
{
public:
	virtual void print() const { std::cout << "Base"; }

	friend std::ostream& operator<<(std::ostream& out, const Base& b)
	{
		out << "Base";
		return out;
	}
};

class Derived : public Base
{
public:
	void print() const override { std::cout << "Derived"; }

	friend std::ostream& operator<<(std::ostream& out, const Derived& d)
	{
		out << "Derived";
		return out;
	}
};

int main()
{
	Base b{};
	std::cout << b << '\n';

	Derived d{};
	std::cout << d << '\n';

	return 0;
}

위의 프로그램을 실행하면 출력은 다음과 같다

Base
Derived

이를 Base ref에 Derived object를 넘겨서 출력해보자

int main()
{
    Derived d{};
    Base& bref{ d };
    std::cout << bref << '\n';

    return 0;
}

이때 출력은 다음과 같다

Base

이는 우리가 기대한 결과가 아니다.

Can we make Operator << virtual?

그렇다면 우리는 operatoro <<을 virtual로 할 수 있을까?
간단히 말하면 불가능하다
첫째, 오직 member function만이 virtualized 가 가능하다
둘째, 가능하다고 해도 operator의 정의를 보면 parameter가 각각 Base, Derived이다

그렇다면 어떻게 해야할까?

The solution

답은 의외로 간단하다
member function을 이용하는 것이다

#include <iostream>

class Base
{
public:
	// Here's our overloaded operator<<
	friend std::ostream& operator<<(std::ostream& out, const Base& b)
	{
		// Delegate printing responsibility for printing to member function print()
		return b.print(out);
	}

	// We'll rely on member function print() to do the actual printing
	// Because print is a normal member function, it can be virtualized
	virtual std::ostream& print(std::ostream& out) const
	{
		out << "Base";
		return out;
	}
};

class Derived : public Base
{
public:
	// Here's our override print function to handle the Derived case
	std::ostream& print(std::ostream& out) const override
	{
		out << "Derived";
		return out;
	}
};

int main()
{
	Base b{};
	std::cout << b << '\n';

	Derived d{};
	std::cout << d << '\n'; // note that this works even with no operator<< that explicitly handles Derived objects

	Base& bref{ d };
	std::cout << bref << '\n';

	return 0;
}

print라는 virtual member function을 이용해 operator<< 에서 실행되도록 해주면 된다
따라서 출력은 다음과 같다

Base
Derived
Derived

profile
청룡동거주민

0개의 댓글