friend 함수, 클래스 올바르게 사용하기

2019. 11. 17. 11:45PL/C++

클래스 간 상호작용을 위해서 friend 키워드가 가끔 사용된다. 캡슐화에 위배되는 사항이라 사용은 지양되지만 실제로 연산자 오버로딩 등 절대적으로 필요한 부분이 있다

 

다음 코드는 클래스 A에 private 멤버에 접근하려고하니 오류가 발생한 것이다

#include <iostream>

using namespace std;

class A {
private:
	int m_value = 1;
};

void printA(A &a) {
	cout << a.m_value << '\n'; // 컴파일 오류
}

int main(void) {
	A a;
	printA(a);
	return 0;
}

 

friend 함수를 정의해서 'printA는 우리와 친구다'라고 A class 안에서 정의할 수 있다

 

#include <iostream>

using namespace std;

class A {
private:
	int m_value = 1;

	friend void printA(A &);
};

void printA(A &a) {
	cout << a.m_value << '\n';
}

int main(void) {
	A a;
	printA(a);
	return 0;
}

 

클래스 하나를 더 확장을 해보자. 그런데 다시 a.m_value 쪽에서 오류가 발생한다

#include <iostream>

using namespace std;

class A {
private:
	int m_value = 1;

	friend void printA(A &, B &);
};

class B {
private:
	int m_value = 2;

	friend void printA(A &, B &);
};

void printA(A &a, B &b) {
	// a.m_value만 오류
	cout << a.m_value << ' ' << b.m_value << '\n'; 
}

int main(void) {
	A a;
	B b;
	printA(a, b);
	return 0;
}

 

 

이유는 class A는 class B 앞에 선언되어 있기 때문에 B의 존재를 알 수가 없기에 식별자 오류를 발생시켰다. 따라서 함수 프로토타입처럼 전방선언을 해줘야만 A는 B의 존재를 이때서야 알게 된다

 

class B;
class A {
	...
};

 

 

friend class는 다음과 같이 클래스를 friend 선언을 통해서 나타낸다

 

#include <iostream>

using namespace std;

class B;
class A {
private:
	int m_value = 1;

	friend class B;
};

class B {
private:
	int m_value = 2;

public:
	void doSomething(A &a) {
		cout << a.m_value << '\n';
	}
};

int main(void) {
	A a;
	B b;
	b.doSomething(a);
	return 0;
}

 

그리고 클래스 전방 선언을 할지라도 그 안의 멤버함수와, 변수의 내용은 알지 못한다. 

아래 코드에서는 class B를 알지만, doSomething이라는 멤버함수가 있는지까지는 모른다

 

#include <iostream>

using namespace std;

class B;
class A {
private:
	int m_value = 1;

	friend void B::doSomething(A &a);
};

class B {
private:
	int m_value = 2;

public:
	void doSomething(A &a) {
		cout << a.m_value << '\n';
	}
};

 

그러면 class B를 올려볼까?

 

#include <iostream>

using namespace std;

class A;
class B {
private:
	int m_value = 2;

public:
	void doSomething(A &a) {
		cout << a.m_value << '\n';
	}
};

class A {
private:
	int m_value = 1;

	friend void B::doSomething(A &a);
};

 

 

그래도 오류가 발생한다. 왜냐하면 이제는 class A가 전방선언이 되어있다고 하지만, A의 멤버변수인 m_value에 대해서는 알지 못한다. 따라서 보통 이러한 경우에는 class A, B가 모두 선언된 후 밑에다 작성을 해야만 한다 

 

#include <iostream>

using namespace std;

class A;
class B {
private:
	int m_value = 2;

public:
	void doSomething(A &);
};

class A {
private:
	int m_value = 1;

	friend void B::doSomething(A &a);
};

void B::doSomething(A &a) {
	cout << a.m_value << '\n';
}

int main(void) {
	A a;
	B b;
	b.doSomething(a);
	return 0;
}