이번 포스팅에서는 friend class가 필요한 상황과 사용 방법을 간단하게 정리하려고 한다.

 

 

 


목차

  • 프렌드 클래스(friend class)란?
  • 프렌드 클래스(friend class)사용 방법
  • 전체 코드

 


프렌드 클래스 (friend class)란?

프렌드 클래스(friend class)란, class에 대한 friend 선언은 original class의 private과 protected의 접근 권한을 또 다른 class에 넘겨주는 것을 뜻한다. 흔히 C++에서 friend하면 friend function만 연상하기 쉽지만, class 또한 friend로 나타낼 수 있다. class에 friend를 사용하는 상황은 리모콘과 TV의 관계를 떠올리면 쉽다. TV에 대한 리모콘은 is-a 관계도 아니며 has-a 관계도 아니다. TV는 리모콘이 아니며 TV는 리모콘을 소유하고 있지도 않다. 즉 둘은 완전히 다른 개별적인 개체들이지만 리모콘은 TV의 기능을 조작하며 다룰 수 있다. 이럴 경우에 class를 friend로 선언해서 사용하게 된다. 

 

 

 


 

프렌드 클래스 (friend class) 사용 방법

friend classoriginal class의 private member와 protected member에 접근할 수 있다. 그리고 더욱 제한을 가해서 특정 class의 member function만 다른 class의 friend가 되도록 할 수도 있다. 다음 코드는 TV와 remote의 관계를 설명하는 friend class의 예제이다. 

 

tv.h
// tv.h -- 푸바오 Tv class, Remote class
#ifndef __TV_H__
#define __TV_H__

/// this is Tv class  
class Tv
{
public:
	friend class Remote;  // Remote class에게 Tv 내부 접근 권한을 허용한다.
	enum {Off, On};
	enum {MinVal, MaxVal = 20};
	enum {Antenna, Cable};
	enum {TV, DVD};

	Tv(int s = Off, int mc = 125) : state(s), volume(5),
		maxchannel(mc), channel(2), mode(Cable), input(TV) { }
	void onoff() { state = (state == On) ? Off : On; }
	bool ison() const { return state == 0; }
	bool volup();
	bool voldown();
	void chanup();
	void chandown();
	void set_mode() { mode = (mode = Antenna) ? Cable : Antenna; }
	void set_input() { input = (input == TV) ? DVD : TV; }
	void settings() const;  // 모든 설정값들의 상태를 출력한다.
private:
	int state;           // On , Off
	int volume;          // 디지털 볼륨이라고 가정
	int maxchannel;      // 최대 채널 수
	int channel;         // 현재 설정된 채널
	int mode;            // 지상파 방송 or 케이블 방송
	int input;           // TV Input or DVD Input
};

// Remote class friend to Tv class
class Remote
{
private:
	int mode;            // TV 조종모드 or DVD 조종모드
public:
	Remote(int m = Tv::TV) : mode(m) { }
	bool volup(Tv& t) { return t.volup(); }
	bool voldown(Tv& t) { return t.voldown(); }
	void onoff(Tv& t) { t.onoff(); }
	void chanup(Tv& t) { t.chanup(); }
	void chandown(Tv& t) { t.chandown(); }
	void set_chan(Tv& t, int c) { t.channel = c; }
	void set_mode(Tv& t) { t.set_mode(); }
	void set_input(Tv& t) { t.set_input(); }
};
#endif

 

  • friend class Remote;
    Tv class 내부에 있는 private와 protected의 대한 접근 권한을 remote에게 부여한다. (friend 선언)
    위치에 따른 차이는 없으니 어디에 선언해도 상관은 없다.
  • void onoff() { state = (state == On) ? Off : On; }
    state의 상태에 따라 조건 연산자를 통해 상태를 변환시킨다.

 

 

특정 function들만 다른 class들에 대해 friend로 만들기

이전에 사용된 코드에서 remote는 실제적으로 Tv class의 private에 접근하는 함수는 remote class의 set_chan() 뿐이다. 그래서 불필요하게 class 자체를 friend로 선언하는거보다 remote가 필요로하는 tv의 함수만 friend로 선언해줄 수 있다. 

class Tv
{
    friend void Remote::set_chan(Tv & t, int c);
    ...
}

 

이렇게하면 기존에 선언해주었던 friend class Remote; 를 생략하고 remote가 필요로 하는 tv 기능만 사용 권한을 넘겨줄 수 있다. 하지만 tv내의 friend void remote:: 부분은 Remote class보다 상단에 선언되어 있어 remote::set_chan 함수를 컴파일러가 인식하지 못한다. 그러므로 사전 선언(forward declaration)을 통해 Tv보다 먼저 Remote를 선언해서 컴파일러에게 알려주어야 한다.

 

Remote의 사전 선언을 통해 위에 문제를 해결한 모습
class Remote;
class Tv
{
    friend void Remote::set_chan(Tv & t, int c);
    ...
}

class Remote
{
    void set_chan(Tv & t, int c);
    ...
}

 

 


 

전체 코드

아래는 Tv와 Remote 의 관계를 friend class 활용해 구현한 모든 코드이다.

 

Tv.h
// tv.h -- 푸바오 Tv class, Remote class
#ifndef __TV_H__
#define __TV_H__

/// this is Tv class  
class Tv
{
public:
	friend class Remote;  // Remote class에게 Tv 내부 접근 권한을 허용한다.
	enum {Off, On};
	enum {MinVal, MaxVal = 20};
	enum {Antenna, Cable};
	enum {TV, DVD};

	Tv(int s = Off, int mc = 125) : state(s), volume(5),
		maxchannel(mc), channel(2), mode(Cable), input(TV) { }
	void onoff() { state = (state == On) ? Off : On; }
	bool ison() const { return state == 0; }
	bool volup();
	bool voldown();
	void chanup();
	void chandown();
	void set_mode() { mode = (mode = Antenna) ? Cable : Antenna; }
	void set_input() { input = (input == TV) ? DVD : TV; }
	void settings() const;  // 모든 설정값들의 상태를 출력한다.
private:
	int state;           // On , Off
	int volume;          // 디지털 볼륨이라고 가정
	int maxchannel;      // 최대 채널 수
	int channel;         // 현재 설정된 채널
	int mode;            // 지상파 방송 or 케이블 방송
	int input;           // TV Input or DVD Input
};

// Remote class friend to Tv class
class Remote
{
private:
	int mode;            // TV 조종모드 or DVD 조종모드
public:
	Remote(int m = Tv::TV) : mode(m) { }
	bool volup(Tv& t) { return t.volup(); }
	bool voldown(Tv& t) { return t.voldown(); }
	void onoff(Tv& t) { t.onoff(); }
	void chanup(Tv& t) { t.chanup(); }
	void chandown(Tv& t) { t.chandown(); }
	void set_chan(Tv& t, int c) { t.channel = c; }
	void set_mode(Tv& t) { t.set_mode(); }
	void set_input(Tv& t) { t.set_input(); }
};
#endif

 

 

Tv.cpp
// tv.h -> Tv class 용
#include <iostream>
#include "tv.h"

bool Tv::volup()
{
	if (volume < MaxVal)
	{
		volume++;
		return true;
	}
	else
		return false;
}

bool Tv::voldown()
{
	if (volume > MinVal)
	{
		volume--;
		return true;
	}
	else
		return false;
}

void Tv::chanup()
{
	if (channel < maxchannel)
		channel++;
	else
		channel = 1;
}

void Tv::chandown()
{
	if (channel > 1)
		channel--;
	else
		channel = maxchannel;
}

void Tv::settings() const
{
	using std::cout;
	using std::endl;
	cout << "TV = " << (state == Off ? "Off" : "ON") << endl; // 조건 연산자 사용
	if (state == On)
	{
		cout << "볼륨 = " << volume << endl;
		cout << "채널 = " << channel << endl;
		cout << "모드 = "
			<< (mode == Antenna ? "지상파 방송" : "케이블 방송") << endl;
		cout << "입력 = " << (input == TV ? "TV" : "DVD") << endl;
	}
}

 

 

use_tv.cpp
// use_Tv.cpp -- Tv와 Remote 클래스를 사용한다
#include <iostream>
#include "tv.h"

int main(void)
{
	using std::cout;
	Tv s42;
	cout << "s42 Tv초기 설정값: \n";
	s42.settings();
	s42.onoff();
	s42.chanup();
	cout << "s42 Tv의 변경된 설정값:\n";
	s42.settings();

	Remote grey;

	grey.set_chan(s42, 10);
	grey.volup(s42);
	grey.volup(s42);
	cout << "리모콘 사용 후 s42 Tv의 설정값:\n";
	s42.settings();

	Tv s58(Tv::On);
	s58.set_mode();
	grey.set_chan(s58, 28);
	cout << "s58 Tv의 설정값:\n";
	s58.settings();
	return 0;
}

 

 


 

'과거 자료' 카테고리의 다른 글

[C++ Basic] Smart Pointer Template Class  (0) 2022.07.10
[C++ Basic] 예외(exception) 메커니즘  (0) 2022.07.07
[#2] Stack  (0) 2022.07.04
[#1] Singly Linked List  (0) 2022.06.25
[C++ Basic] 클래스 템플릿 (Class Template)  (0) 2022.06.21