728x90

1. friend 개념

- 클래스의 멤버 함수는 아니지만, 해당 클래스의 private 멤버에 접근할 수 있도록 하는 도구

- 형태: friend 함수 / friend 클래스 / friend 연산자 오버로딩

** friend 함수는 멤버함수가 아니므로 .이나 -> 통해 호출 불가능

** 그러나 private 멤버변수에 대해, 멤버함수와 동등한 접근 권한을 가짐

 

* 주의

- friend는 비공개 멤버에 대한 접근을 허용하는 기능이므로 남용하지 않는 것이 안전

- 클래스 간의 관계를 명확하게 구성하고, 필요한 경우에만 friend 사용할

 

2. friend를 사용하는 주요 경우

2-1. friend 함수: '함수'를 클래스의 freind로 선언

해당 함수는 클래스의 멤버 함수가 아니지만 클래스의 private 멤버에 접근할 수 있게 됨

class MyClass {
private:
    int privateData;

public:
    MyClass(int data) : privateData(data) {}
    friend void friendFunction(MyClass obj); // 'friend 함수' 선언};

→ friendFunction 함수는 MyClass 클래스 '외부'에서 정의되어 있음

외부에서 정의된 함수가 MyClass의 멤버 변수에 접근하려면, MyClass 클래스 내부에 그것의 원형이 선언되어 있어야 함

→ 더 원하는 친구가 직접 발품 팔기.~! ㅎㅎ

 

 

2-2. friend 클래스: '클래스'를 다른 클래스의 friend로 선언

다른 클래스의 private 멤버에 접근할 수 있게 됨

class FriendClass {
private:
    int secretData;
public:
    FriendClass(int data) : secretData(data) {}};


class MyClass {
private:
    int privateData;
public:
    MyClass(int data) : privateData(data) {}
    friend class FriendClass; // FriendClass는 MyClass의 private member에 접근할 수 있음};

→ 마찬가지로, FriendClass 역시 MyClass '외부'에 정의되어 있음 

 

2-3. friend 함수와 friend 클래스를 모두 사용하는 경우

#include <iostream>

class FriendClass;

class MyClass {
private:
    int privateData;

public:
    MyClass(int data) : privateData(data) {}

    // FriendClass를 friend 클래스로 선언
    friend class FriendClass;

    void PrintPrivateData() {
        std::cout << "MyClass privateData: " << privateData << std::endl;
    }
};

class FriendClass {
private:
    int secretData;

public:
    FriendClass(int data) : secretData(data) {}

    void AccessMyClassPrivateData(MyClass& obj) {
        std::cout << "FriendClass accessing MyClass privateData: " << obj.privateData << std::endl;
    }
};

int main() {
    MyClass myObj(42);
    FriendClass friendObj(100);

    myObj.PrintPrivateData(); // MyClass의 멤버 함수를 통한 privateData 접근
    friendObj.AccessMyClassPrivateData(myObj); // FriendClass를 통한 privateData 접근

    return 0;
}

연산자 오버로딩에서 friend가 사용되는 사례

- 어떤 클래스에 이항 연산자를 오버로딩할 경우 friend 필요한 경우 발생함 (*이항 연산자 : 개의 피연산자를 요구하는 연산자)

 

(1) friend만을 이용해서 연산자 오버로딩 하는 경우

(단, 입력 매개변수가 'int * 클래스' 순서를 지켜야 함)

 

time.h

#include<iostream>
using namespace std;

#ifndef FIRE_C_TIME_H
#define FIRE_C_TIME_H

class Time{
private:
    int hours;
    int mins;
public:
    Time();
    Time(int, int);
    void show();
    ~Time();
    
    friend Time operator*(int n, Time& t); //friend를 활용한 연산자 오버로딩
};

#endif //FIRE_C_TIME_H

time_func.cpp

#include "time.h"

Time::Time(){
    hours = 0;
    mins = 0;}

Time::Time(int h, int m){
    hours = h;
    mins = m;}

void Time::show(){
    cout << hours << "시간 " << mins << "분" << endl;}

Time::~Time(){}

// friend 통해 선언한 함수를 정의할 때
// 그것은 멤버함수가 아니므로 클래스 귀속 :: 표시도 하지 않고, friend를 명시하지도 않음
// 매개변수 입력 순서 중요
Time operator*(int n, Time& t){ //n*t로 해석됨 
    Time result;
    long resultMin = t.hours * n * 60 + t.mins * n;
    result.hours = resultMin / 60;
    result.mins = resultMin % 60;
    return result;
}

main.cpp

#include "time.h"
#include "time_func.cpp"

//c++ friend: public 이외에도 private 멤버변수에 접근할 수 있는 또 다른 방법
int main(){

    Time t1(1, 20);
    Time t2;
    Time t3;

    t2 = 3 * t1; //순서 바뀌면 안 됨
    t2.show();
    
    return 0;
}

(2) 사실.. 굳이 friend 쓰지 않아도 구현됨 (단, 입력 매개변수가 '클래스 * int' 순서를 지켜야 함)

 

time.h

#include<iostream>
using namespace std;

#ifndef FIRE_C_TIME_H
#define FIRE_C_TIME_H

class Time{
private:
    int hours;
    int mins;
public:
    Time();
    Time(int, int);
    void show();
    ~Time();

    Time operator*(int n);
};

#endif //FIRE_C_TIME_H

time_func.cpp

#include "time.h"

Time::Time(){
    hours = 0;
    mins = 0;}

Time::Time(int h, int m){
    hours = h;
    mins = m;}

void Time::show(){
    cout << hours << "시간 " << mins << "분" << endl;}

Time::~Time(){}

// friend를 사용하지 않고 클래스의 멤버함수로 정의할 때
Time Time::operator*(int n){
    Time result;
    long resultMin = hours * n * 60 + mins * n;
    result.hours = resultMin / 60;
    result.mins = resultMin % 60;
    return result;
}

main.cpp

#include "time.h"
#include "time_func.cpp"

int main(){

    Time t1(1, 20);
    Time t2;

    t2 = t1 * 4;
    t2.show();

    return 0;
}

//5시간 20분

(3) 두 개의 입력 매개변수 순서를 자유롭게 하고 싶을 때 ~!

→ 그러면 friend 이용하는 경우와 이용하지 않는 경우 모두 활용하면 됨 (단순..)

 

time.h

#include<iostream>
using namespace std;

#ifndef FIRE_C_TIME_H
#define FIRE_C_TIME_H

class Time{
private:
    int hours;
    int mins;
public:
    Time();
    Time(int, int);
    void show();
    ~Time();

    Time operator*(int n); //멤버함수
    friend Time operator*(int, Time&); //friend 함수
};

#endif //FIRE_C_TIME_H

time_func.cpp

#include "time.h"

Time::Time(){
    hours = 0;
    mins = 0;}

Time::Time(int h, int m){
    hours = h;
    mins = m;}

void Time::show(){
    cout << hours << "시간 " << mins << "분" << endl;}

Time::~Time(){}


// friend를 사용하지 않고 클래스의 멤버함수로 정의할 때
Time Time::operator*(int n){
    Time result;
    long resultMin = hours * n * 60 + mins * n;
    result.hours = resultMin / 60;
    result.mins = resultMin % 60;
    return result;
}

// friend 통해 선언한 함수를 정의할 때
// 그것은 멤버함수가 아니므로 클래스 귀속 :: 표시도 하지 않고, friend를 명시하지도 않음
Time operator*(int n, Time& t){
    return t*n;
}

main.cpp

#include "time.h"
#include "time_func.cpp"

int main(){

    Time t1(1, 20);
    Time t2;

    t2 = t1 * 4;
    t2.show();

    t2 = 4 * t1;
    t2.show();

    return 0;
}

/*5시간 20분
5시간 20분*/

 

728x90

+ Recent posts