Turbo-C
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
터보-C 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
Lua 게시판
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C/C++ Q/A
[945] friend 함수는 클래스의 캡슐화에 위배되는 것이 아닙니다.
김백일 [cedar] 1697 읽음    2002-08-03 16:52
프렌드 함수는 보통 연산자 겹지정(operator overloading)을 위해 사용됩니다.

다음과 같은 2차원 벡터를 나타내는
Vector(std::vector가 아닙니다.)라는 클래스를 정의해보죠.
(다음은 'C++ 기초 플러스'(성안당)에 있는 내용을 정리한 겁니다.)
멤버 함수로
두 벡터의 덧셈, 뺄셈인 +과 - 연산과
상수를 곱하는 * 연산을 정의한다면 다음과 같습니다.

class Vector
{
private:
  double x, y;
public:
  Vector(double _x, double _y) : x(_x), y(_y) {};
  Vector(const Vector& v) { x = v.x; y = v.y; }
  double GetX() { return x; }
  double GetY() { return y; }
  void SetX(double _x) { x = _x; }
  void SetY(double _y) { y = _y; }
  Vector operator+(const Vector& b) { return Vector(x + b.x, y + b.y); }
  Vector operator-(const Vector& b) { return Vector(x - b.x, y - b.y); }
  Vector operator*(double n) { return Vector(n * x, n * y); }
}

사용할 때는

Vector a(1.0, 2.0), b(3.0, 4.0),
  sum = a + b, diff = a - b;

라고 하면, 컴파일러가 다음과 같이 바꿉니다.

sum = a.operator+(b), diff = a.operator-(b);

물론, sum은 (4.0, 6.0)은 diff는 (-2.0, -2.0)가 됩니다.

operator*()를 테스트하려면

Vector mul = a * 2.0;

이라고 쓰면,
mul = a.operator*(2.0);
가 되어 mul이 (2.0, 4,0)이 되는데요,
만약 다음과 같이

Vector mul = 2.0 * a;

라고 쓰면, 어떻게 될까요?
컴파일러가 다음과 같이 변형하게 되는데,

mul = 2.0.operator*(a);

물론, 컴파일 에러가 나게 됩니다.

이런 문제를 해결하려면,
operator*()를 멤버 함수가 아니라 다음과 같이 프렌드 일반 함수로 정의하면 됩니다.

class Vector {
private:
  ...
public:
  ...
  friend Vector operator*(const Vector& a, double n);
  friend Vector operator*(double n, const Vector& a);
}

// 이렇게 짧은 함수는 inline을 붙이면 성능 향상에 도움이 됩니다.
inline Vector operator*(const Vector& a, double n)
{
  return Vector(a.x * n, a.y * n);
}

inline Vector operator*(double n, const Vector& a)
{
  return Vector(n * a.x, n * a.y);
}


그러면

Vector mul = 2.0 * a;



Vector mul = operator*(2.0, a)

로 바뀌므로 문제 없이 컴파일됩니다.

이번에는 다른 문제를 생각해보죠.

연산자 겹지정을 할 때는, 멤버 함수 대신 프렌드 일반 함수를 쓰실 것을 권합니다.
operator+()와 operator-()의 경우도,

class Vector {
  ...
  friend Vector operator+(const Vector& a, const Vector& b)
  friend Vector operator-(const Vector& a, const Vector& b)
  ...
}

inline Vector operator+(const Vector& a, const Vector& b)
{
  return Vector(a.x + b.x, a.y + b.y);
}

inline Vector operator-(const Vector& a, const Vector& b)
{
  return Vector(a.x - b.x, a.y - b.y);
}

라고 쓰면, 대칭적인 코드가 되기 때문에 가독성이 더 좋습니다.


또다른 예를 들어보죠.

Vector를 출력하려면 어떻게 해야 할까요?

예를 들어 다음과 같이 멤버함수로 정의해보죠.

class Vector
{
  ...
  void operator<<(ostream& os, const Vector& v);
  ...
};

inline void Vector::operator<<(ostream& os, const Vector& v)
{
  os << "(" << x << "," << y << ")";
}


라고 한다면,

Vector v;

일때

cout << v;

라고 쓸 수는 없습니다.

cout.operator<<(v);

로 변형하면

cout::operator<<(const Vector& v)

가 호출되어야 하는데, 이런 함수는 정의되어 있지 않기 때문이죠.

그러므로, 대신

v << cout;

이라고 쓸 수 밖에는 없습니다. 상당히 어색하지요. -_-;

그래서 다음과 같이 프렌드 일반 함수로 정의합니다.

class Vector
{
  ...
  friend ostream& operator<<(ostream& os, const Vector& v);
  ...
};

inline ostream& operator<<(ostream& os, const Vector& v)
{
  os << "(" << x << "," << y << ")";
  return os;
}

여기서 return 값을 ostream& 으로 한 것은 다음과 같이 연속해서 출력하는 경우를 위해서 입니다.

cout << v << "is vector." << endl;

ostream& 리턴값이 없다면,

cout << v;

라고 쓸 수 밖에는 없죠.

하여튼 여기서는

operator<<(cout, v)

가 호출되므로 문제없이 컴파일 됩니다.

:
: 주의사항 : friend 함수는 클래스의 추상화에 위배가 되기때문에
: 많이 사용하면 안좋다고 그러네요..^^;
: 그러니까 꼭 필요할때만 사용하시면 됩니다..

이것은 추상화라기보다는 캡슐화라는 겁니다.

friend 함수는 클래스의 캡슐화에 위배되는 것이 아닙니다.
단지 멤버 함수를 다른 표현으로 바꾼 것에 불과합니다.
클래스 내부에서 (friend라는 키워드를 붙여서) 선언을 하지 않으면
쓸 수 없는 것은 멤버 함수와 마찬가지입니다.

다시 한 번 강조하지만, 연산자 겹지정을 할 때는 멤버 함수대신 프렌드 일반 함수를 사용하세요.
코드의 가독성도 높아지고, 코딩 에러도 줄일 수 있는 좋은 방법입니다.


+ -

관련 글 리스트
935 friend 이해가 잘안갑니다. 김경래 1704 2002/08/01
940     Re:friend 이해가 잘안갑니다. 오전&오후 1717 2002/08/02
945         friend 함수는 클래스의 캡슐화에 위배되는 것이 아닙니다. 김백일 1697 2002/08/03
952             Re:friend 함수는 클래스의 캡슐화에 위배되는 것이 아닙니다. 오전&오후 1993 2002/08/05
953                 [펌]friend는 OOP에 충실하지 않을 것일까? 김백일 1784 2002/08/05
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.