본문 바로가기
c++

22. [C++] friend

by yoonjunho 2023. 1. 20.

커피 머신으로 커피를 내려 마실 때 우리가 알아야 하는 것은 커피를 내리는 방법이지 커피 머신의 내부 동작이나 상세 구조를 반드시 알 필요는 없다. 사용자가 몰라도 되는 불필요한 정보 혹은 사용자가 함부로 건드릴 경우 위험한 정보는 숨기고 필요한 최소한의 정보만으로 객체를 쉽게 사용할 수 있도록 하는 것이 정보 은폐이다.

 

1. 멤버 함수의 가시성

객체지향 프로그래밍에서도 필요한 기능공개하고 몰라도 되는 부분숨겨서 객체를 설계한다.

c++언어에서는 private, public, protected같은 접근 지정자를 이용하여 클래스의 정보 은폐 기능, 누구를 숨길지 누구를 공개할지 등을 구성할 수 있다. 공개된 멤버는 외부에서 자유롭게 접근할 수 있지만 공개되지 않은 멤버를 읽으려고 하면 컴파일 과정에서 에러가 발생하게 된다.

 

class Date{

private:

    int yaer, mon, day;

public:

    void SetDate(int y, int m, int d);

    void GetDate();

};

 

유사한 클래스를 설계하거나 기존 클래스의 내부를 변경할 경우 public으로 공개되 ㄴ부분은 유지한 채 private으로 숨겨진 부분을 프로그래머의 기호에 맞게 변경하여도 사용자는 사용하는 데 있어 변화를 느끼거나 불편함을 느끼지 못하게 된다.

 

정보를 은폐하면 객체의 신뢰성이 높아지고 기능 개선이 용이하게 된다.

 

2. friend

일단 정보를 은폐하면 객체의 신뢰성이 높아지고 기능 개선은 용이해지지만 멤버들에 접근하고자 할 때는 불편해질 수 있따.

 

프렌드(friend)는 명시적으로 지정한 대상에 대해 모든 메메버를 공개하도록 하는 방법이다.

즉, 프렌드는 객체지향 프로그래밍의 특징 중 하나인 정보 은폐에 대한 예외 사항이다. 그러므로 너무 자주 사용하는 것은 좋지 않으며 반드시 필요한 경우에만 사용해야 한다.

전역함수, 클래스, 멤버 함수를 프랜드로 지정할 수 있다.

 

프랜드 함수

어떤 클래스 내에서 프렌드 함수클래스의 모든 멤버들에  접근 지정자에 관계없이 접근할 수 있는 권한을 부여받은 함수이다

 

실습 예제 6-1 :

*참조자에 의한 call by referecne

https://yoonjunho.tistory.com/157

 

[C++] 2가지 call by reference(주솟값, 참조자 이용)

call by reference : 참조에 의한 호출 : 메모리 주솟값을 넘기는 방식 void swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } call by reference variable : 참조자를 이용한 참조에 의한 호출 int a=1; int b=2; swap(a,b) v

yoonjunho.tistory.com

#include <iostream>
using namespace std;

class Color;

class Position {
	friend void GetInfo(Color& c, Position& p);
private:
	int cx, cy, cr;//원의 중심 좌표와 반지름
public:
	Position(int m_x, int m_y, int m_r) {
		cx = m_x;
		cy = m_y;
		cr = m_r;
	}
};

class Color {
	friend void GetInfo(Color& c, Position& p);
private:
	int r, g, b; //           원 내부 색상
public:
	Color(int m_r, int m_g, int m_b) {
		r = m_r;
		g = m_g;
		b = m_b;
	}
};

void GetInfo(Color& c, Position& p) {
	cout << "RGB:: " << c.r << "," << c.g << "," << c.b << endl;//.을 쓰면 된다.
	cout << "Position:: " << p.cx << "," << p.cy << "," << p.cr << endl;
}

int main(void) {
	Color C(255, 255, 255);
	Position P(100, 100, 10);
	GetInfo(C, P);

	return 0;
}

ㄴ 이것도 되고 (참조자에 의한 call - by - reference)

 

#include <iostream>
using namespace std;

class Color;

class Position {
	friend void GetInfo(Color* c, Position* p);
private:
	int cx, cy, cr;//원의 중심 좌표와 반지름
public:
	Position(int m_x, int m_y, int m_r) {
		cx = m_x;
		cy = m_y;
		cr = m_r;
	}
};

class Color {
	friend void GetInfo(Color* c, Position* p);
private:
	int r, g, b; //           원 내부 색상
public:
	Color(int m_r, int m_g, int m_b) {
		r = m_r;
		g = m_g;
		b = m_b;
	}
};

void GetInfo(Color* c, Position* p) {
	cout << "RGB:: " << (* c).r << "," << (*c).g << "," << (*c).b << endl;//.을 쓰면 된다.
	cout << "Position:: " << ( * p).cx << "," << (*p).cy << "," << (*p).cr << endl;
}

int main(void) {
	Color C(255, 255, 255);
	Position P(100, 100, 10);
	GetInfo(&C, &P);

	return 0;
}

ㄴ 이것도 된다. (주솟값에 의한 call - by - reference)

 

6번째 줄에서는 Date 클래스와 Time 클래스 내부에서 GetInfo() 전역 함수를 프랜드로 지정하였다.

GetInfo()함수는 클래스 멤버 함수와 동일하게 해당 클래스의 모든 멤버에 자유롭게 접근할 수 있는 특권을 가지게 된다.

 

21~24번째 줄에 구현된 GetInfo()함수는 클래스 내부의 private으로 지정된 각 멤버에 자유롭게 접근할 수 있다.

 

만약 GetInfo()를 프랜드로 지정하지 않을 경우, 즉 friend키워드를 삭제할 경우  private때문에 컴파일 에러가 발생하게 된다.