출처 :
- 명품 C++ Programming (저자 황기태)
- 객체지향프로그래밍
- 블뎁블뎁
프렌드 함수
클래스의 멤버로 선언하긴 좀 그렇고, 내부에 접근하게 만들고는 싶을 때
- 클래스의 멤버 함수가 아닌 외부 함수
- 클래스 외부에 선언된 전역 함수
- 다른 클래스의 멤버 함수
- 다른 클래스의 모든 멤버 함수
- class Rect { // 전역 함수 equals()를 Rect 클래스에 프렌드로 선언 friend bool equals(Rect r, Rect s); }; class Rect { // RectManager 클래스의 equals() 멤버 함수를 Rect 클래스의 프렌드로 선언 friend bool RectManager::equals(Rect r, Rect s); }; class Rect { // RectManager 클래스의 모든 멤버 함수를 Rect 클래스에 프랜드로 선언 friend RectManager; };
- friend 키워드로 클래스 내에 선언된 함수
- 클래스의 모든 멤버에 접근할 수 있는 권한 부여
- 프렌드 함수라고 부름
- 프렌드 선언의 필요성
- 클래스의 멤버로 선언하기에는 무리가 있고, 클래스의 모든 멤버를 자유롭게 접근할 수 있는 일부 함수 작성시
- 클래스 멤버로는 적합하지 않지만, private protected 멤버를 접근해야하는 특별한 경우
- 프렌드 함수 개수에 제한 없음
#include <iostream>
using namespace std;
class Rect; // Rect 클래스가 선언되기 전에 먼저 참조되는 컴파일 오류를 막기 위한 선언문
bool equals(Rect r, Rect s);
class Rect {
int width, int height;
public:
Rect(int width, int height) {
this->width = width;
this->height = height;
}
friend bool equals(Rect r, Rect s); // Recet의 멤버함수가 아님
};
// Rect r과 s 복사 생성
bool equals(Rect r, Rect s) {
// 객체 외부에서 private 멤버에 접근한다.
// 이게 가능한 이유는 Rect 에서 equals를 friend 삼았기 떄문
if (r.width == s.width && r.height == s.height) return ture;
else return false;
}
int main() {
Rect a(3,4), b(4,5);
if (equals(a,b)) cout << "equal" << endl;
else cout << "not equal" << endl;
}
다른 클래스의 멤버 함수를 프렌드로 선언
#include <iostream>
using namespace std;
// Rect 클래스가 선언되기 전어 먼저 참조되는 컴파일 오류를 막기 위한 선언문
class Rect;
class RectManager {
public:
bool equals(Rect r, Rect s);
};
class Rect {
int width, height;
public:
Rect(int width, int height) { this->width = width; this-> height = height; }
// 어느 클래스에서 왔는지 지정
friend bool RectManager::equals(Rect r, Rect s);
};
bool RectManager::equals(Rect r, Rect s) {
if (r.width == s.widht && r.height == s.height) return true;
else return false;
}
int main() {
Rect a(3,4), b(3,4);
RectManger man;
if (man,equals(a,b)) count << "equal" << endl;
else cout << "not equal" << endls;
}
다른 클래스 전체를 프렌드로 선언
#include <iostream>
using namespace std;
class Rect; // Rect 클래스가 선언되기 전어 먼저 참조되는 컴파일 오류를 막기 위한 선언문
class RectManager {
public:
bool equals(Rect r, Rect s);
void copy(Rect& dest, Rect& src);
};
class Rect {
int width, height;
public:
Rect(int width, int height) { this->width = width; this-> height = height; }
// 어느 클래스에서 왔는지 지정
friend RectManager;
};
bool RectManager::equals(Rect r, Rect s) {
if (r.width == s.widht && r.height == s.height) return true;
else return false;
}
void RectManger::copy(Rect& dest, Rect& src) {
dest.width = src.width;
dest.height = src.height;
}
연산자 중복 operator overloading
- 본래부터 있던 연산자만! 새로운 의미 정의
- 일종의 다형성 polymorphism
- 높은 프로그램 가독성
- 피연산자 타입이 다른 새로운 연산 정의
- 연산자는 함수 형태로 구현
- 반드시 클래스와 관계를 가짐
- 피연산자의 개수를 바꿀 수 없음
- 연산의 우선 순위 변경 안됨
- 모든 연산자가 중복 가능하지 않음 - . .* :: 범위지정연산자 ? : 3항연산자 등등…
연산자 함수 구현 방법 2가지
리턴타입 operator연산자 (매개변수리스트);
- 클래스의 멤버 함수로 구현
- Color operator+ (Color op1, Color op2); bool operator== (Color op1, Color op2); class Color { friend Color operator+ (Color op1, Color op2); friend bool operator== (Color op1, Color op2);
- 외부 함수로 구현하고 클래스에 프렌드 함수로 선언
- class Color { // 나와 비교하려는 객체를 받아서 나에게 더한다. // 왼쪽 피연산자는 객체 자신이므로 매개 변수에 전달되지 않는다. // 오른쪽 피연산자가 op2에 전달 Color operator+ (Color op2); bool operator== (Color op2); };
+ 연산자 중복
// c = a + b; -> C = a.operator+(b); b가 인수로서 전달
class Power {
int kick;
int punch;
public:
Power(int kick=0, int punch=0) {
this->kick = kick; this->punch = punch;
}
// 클래스의 멤버 함수로 구현하는 거니까 friend를 쓰면 안된다.
// Power& op2로 해도 된다~
Power operator+ (Power op2);
Power operator+ (int op2);
};
// 묵시적으로 op2 복사
Power Power::operator+(Power op2) {
// 더해질 새로운 객체
Power tmp;
// 나의 kick에 op2의 kick을 더함
tmp.kick = this->kick + op2.kick;
tmp.punch = this->punch + op2.punch;
return tmp;
}
Power Power::operator+(int op2) {
Power tmp;
tmp.kick = kick + op2;
tmp.punch = punch + op2;
return tmp;
}
== 연산자 중복
// a == b; -> a.operator==(b);
#include <iostream>
using namespace std;
class Power {
int kick;
int punch;
public:
Power(int kick=0, int punch=0) {
this->kick = kick; this->punch = punch;
}
void show();
bool operator== (Power op2);
};
bool Power::operator==(Power op2) {
if (kick == op2.kick&& punch == op2.punch) return true;
else return false;
}
+= 연산자 중복 (참조 반환 주의!!!)
// c = a += b; -> c = a.+=(b);
// 업데이트된 a를 c에 대입
class Power {
int kick;
int punch;
public:
Power& operator+= (Power op2);
}
// 자기 자신 참조를 반환
Power& Power::operator+=(Power op2) {
// this-> 생략됨
kick = kick + op2.kick;
punch = punch + op2.punch;
return *this;
}
단항 연산자 중복
단항 연산자
- 피연산자가 하나 뿐인 연산자
- 전위 연산자, 후위 연산자
멤버 함수로 구현
전위 ++ 연산자 중복 (시험문제 나옴)
// ++a -> a.++()
class Power {
int kick;
int punch;
public:
Power(int kick=0, int punch=0) {
this->kick = kick; this->punch = punch;
}
void show();
Power& operator++();
bool operator!();
};
void Power::show() {
cout << "kick=" << kick << ',' << "punch=" << punch << endl;
}
Power& Power::operator++() { // 매개변수
// 멤버변수와 매개 변수 이름이 같을때 this를 씀. 여기서는 뭐 굳이?
kick++;
punch++;
// 갱신된 객체 자신의 참조 리턴
return *this;
}
bool Power::operator!() {
if (kick == 0 && punch == 0) return true;
else return false;
}
후위 ++ 연산자 중복 (시험문제 나옴)
// ++a -> a.++(임의의 정수)
class Power {
int kick;
int punch;
public:
Power(int kick=0, int punch=0) {
this->kick = kick; this->punch = punch;
}
void show();
// 매개 변수 있음!! 전위 연사자와 구별하려고
// 주의! 연산자 함수는 디폴트 매개변수를 가질 수 없다.
Power operator++(int x);
bool operator!();
};
void Power::show() {
cout << "kick=" << kick << ',' << "punch=" << punch << endl;
}
// 주의! 연산자 함수는 디폴트 매개변수를 가질 수 없다.
// 컴파일러가 자동으로 x에 0 대입
Power Power::operator++(int x) {
// 증가 이전의 객체 상태를 저장
Power tmp = *this;
kick++;
punch++;
// 증가 이전 객체 상태 리턴
return tmp;
}
bool Power::operator!() {
if (kick == 0 && punch == 0) return true;
else return false;
}
프렌드로 구현
// ++a -> a.++(임의의 정수)
class Power {
int kick;
int punch;
public:
Power(int kick=0, int punch=0) {
this->kick = kick; this->punch = punch;
}
void show();
Power operator++(int x); // 매개 변수 있음!! 전위 연사자와 구별하려고
bool operator!();
};
void Power::show() {
cout << "kick=" << kick << ',' << "punch=" << punch << endl;
}
Power Power::operator++(int x) {
// 증가 이전의 객체 상태를 저장
Power tmp = *this;
kick++;
punch++;
// 증가 이전 객체 상태 리턴
return tmp;
}
bool Power::operator!() {
if (kick == 0 && punch == 0) return true;
else return false;
}
2 + a 덧셈을 위한 + 연산자 함수 작성
// b = 2 + a; -> b = +(2,a);
// 2는 클래스 아닌 기본타입이라 b = 2.+(a);로 변환이 불가능하다
class Power {
int kick;
int punch;
public:
Power(int kick=0, int punch=0) {
this->kick = kick; this->punch = punch;
}
void show();
friend Power operator+(int op1, Power op2);
};
Power operator++(int op1, Power op2) {
Power tmp;
// private 속성인 kick, punch를 접근하기 위해 연산자 함수를 friend로 선언해야함
tmp.kick = op1 + op2.kick;
tmp.punch = op1 + op2.punch;
return tmp;
}
+연산자를 외부 프렌드 함수로 구현
// c = a + b; -> c = +(a,b);
class Power {
int kick;
int punch;
public:
Power(int kick=0, int punch=0) {
this->kick = kick; this->punch = punch;
}
void show();
friend Power operator+(Power op1, Power op2);
};
Power operator+(Power op1, Power op2) {
Power tmp;
tmp.kick = op1.kick + op2.kick;
tmp.punch = op1.punch + op2.punch;
return tmp;
}
참조를 리턴하는 << 연산자 작성
- 연속적으로 더하는 연산을 하기 위해 원본(*this)에 대한 참조를 반환해야한다.
Power& operator<< (int n);
Power& Power::operator<< (int n) {
kick += n;
punch += n;
return *this;
}
'[전공]' 카테고리의 다른 글
[명품 C++] 9장 가상 함수와 추상 클래스 (1) | 2022.06.06 |
---|---|
[명품 C++] 08 상속 (0) | 2022.06.06 |
[명품 C++] 6장 함수 중복과 static 멤버 (3) | 2022.06.05 |
[명품 C++] 05 함수와 참조, 복사 생성자 (6) | 2022.06.05 |
[명품 C++] 04 객체 포인터와 객체 배열, 객체의 동적 생성 (0) | 2022.06.02 |