Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
05-17 00:00
관리 메뉴

nomad-programmer

[Programming/C++] 전역 함수를 이용한 연산자 오버로딩 본문

Programming/C++

[Programming/C++] 전역 함수를 이용한 연산자 오버로딩

scii 2023. 1. 20. 11:51

연산자 오버로딩에는 다음 두 가지가 있다.

  • 첫째, 멤버 함수를 이용한 연산자 오버로딩
  • 둘째, 전역 함수를 이용한 연산자 오버로딩

일반적으로 멤버 함수를 이용한 연산자 오버로딩을 사용한다. 멤버 함수를 이용한 연산자 오버로딩을 사용할 수 없을 때는 전역 함수 연산자 오버로딩을 사용한다.

멤버 함수를 이용한 연산자 오버로딩을 사용할 수 없는 경우

이항 연산의 왼쪽 항이 연산자 오버로딩 객체가 아니면 멤버 함수를 이용한 연산자 오버로딩을 이용할 수 없다. 이항 연산의 왼쪽 객체를 기준으로 연산자 오버로딩 멤버 함수를 호출하기 때문이다. 예를 들어 보자.

class Point
{
    ...
};

int main()
{
    Point p1(1, 2), pt2(3, 4);
    pt1 + pt2;  // pt1.operator+(p2)
    
    return 0;
}

위에서 p1 + p2의 이항 연산은 p1을 this 객체로 멤버 함수를 pt1.operator+(pt2)와 같이 호출한다. 그러므로 왼쪽 항이 자신의 객체(연산자 오버로딩 객체)가 아니라면 아래처럼 멤버 함수를 호출할 수 없으며 전역 함수 연산자 오버로딩을 사용해야 한다.

class Point
{
    ...
};

int main()
{
    Point pt1(1, 2);
    
    k + p1;
    // 여기서 k는 연산자 오버로딩 객체가 아니므로 k.operator+(p1) 처럼 호출할 수 없다.
    // operator+(k, pt1) 처럼 호출해야 한다.
    
    return 0;
}

연산자 오버로딩은 컴파일러가 p1 == p2;와 같은 코드를 두 가지로 해석한다.

  1. 멤버 함수로 p1.operator==(p2); 처럼 해석하며, 이것은 p1의 operator==() 멤버 함수를 호출해 p2를 인자로 전달한다.
  2. 전역 함수로 operator==(p1, p2); 처럼 해석하며, 이것은 전역 함수 operator==()의 인자로 p1와 p2 객체를 각각 전달한다.

멤버 함수를 이용한 연산자 오버로딩

멤버 함수를 이용한 -연산자 오버로딩이다.

#include <iostream>

using namespace std;

class Point {
public:
	Point(int _x = 0, int _y = 0) : x(_x), y(_y) {}
	void Print() const { cout << x << ',' << y << endl; }
	int GetX() const { return x;  }		// x의 getter
	int GetY() const { return y;  }		// y의 getter

	const Point operator-(const Point& ref) const {
		return Point(x - ref.x, y - ref.y);
	}

private:
	int x;
	int y;

};

int main() {
	Point p1(2, 3), p2(5, 5);
	Point p3;

	p3 = p1 - p2;
	p3.Print();

	return 0;
}


// 결과
-3, -2

p1 - p2는 p1의 멤버 함수 p1.operator-(p2)를 호출한다. p2는 인자로 전달된다.


전역 함수를 이용한 연산자 오버로딩

다음의 예제는 전역 함수를 이용한 - 연산자 오버로딩이다.

#include <iostream>

using namespace std;

class Point {
public:
	Point(int _x = 0, int _y = 0) : x(_x), y(_y) {}
	void Print() const { cout << x << ',' << y << endl; }
	int GetX() const { return x;  }		// x의 getter
	int GetY() const { return y;  }		// y의 getter

private:
	int x;
	int y;

};

const Point operator-(const Point& ref1, const Point& ref2) {
	return Point(ref1.GetX() - ref2.GetX(), ref1.GetY() - ref2.GetY());
}

int main() {
	Point p1(2, 3), p2(5, 5);
	Point p3;

	p3 = p1 - p2;
	p3.Print();

	return 0;
}


// 결과
-3, -2

p1 - p2는 전역 함수 operator-(p1, p2)를 호출한다. p1과 p2는 인자로 전달된다. operator-(p1, p2); 이렇게 전달된다.

전역 함수를 이용하면 Point 클래스의 private 멤버인 x, y에 접근할 수 없으므로 getter를 이용하거나 friend 함수를 사용해야 한다.

friend 함수를 사용하는 코드는 다음과 같다.

friend const Point operator-(const Point& ref1, const Point& ref2) const {
    return Point(ref1.x - ref2.x, ref1.y - ref2.y);
}

이렇게 게터(getter)나 세터(setter)를 사용하지 않고 x, y에 직접 접근할 수 있다. friend 함수는 캡슐화를 저해하므로 가능하면 getter, setter를 사용하는 방법이 좋다.


friend 키워드

friend에는 함수 friend와 클래스 friend, 두 가지가 있다. 함수나 클래스를 friend로 지정하면, 모든 클래스 멤버(private, protected, public)를 접근 제한 없이 사용할 수 있다. 함수 friend는 다음과 같이 지정한다.

class A {
    ...
    friend void Func();
};

void Func() {
    // class A의 모든 멤버를 접근 제한 없이 사용할 수 있다.
}

 클래스 friend는 다음과 같이 지정한다.

class A {
    ...
    friend class B;
}

class B {
    // class A의 모든 멤버를 접근 제한 없이 사용할 수 있다.
}
Comments