12.15 Friend functions and classes
https://www.learncpp.com/cpp-tutorial/friend-functions-and-classes/
Friend functions
friend function 이란 일반 함수인데 member의 private value에 접근할 수 있도록 허용해주는 키워드 이다
다음의 예시를 보자
class Accumulator
{
private:
int m_value { 0 };
public:
void add(int value) { m_value += value; }
// Make the reset() function a friend of this class
friend void reset(Accumulator& accumulator);
};
// reset() is now a friend of the Accumulator class
void reset(Accumulator& accumulator)
{
// And can access the private data of Accumulator objects
accumulator.m_value = 0;
}
int main()
{
Accumulator acc;
acc.add(5); // add 5 to the accumulator
reset(acc); // reset the accumulator to 0
return 0;
}
void reset이라는 function이 accumulator라는 Accumulator 클래스의 변수를 parameter로 받고 있다
원래대로라면 reset은 accumulator의 private variable에 접근할 수 없어야 하지만
friend라는 키워드로 접근을 허용해주었기 때문에 m_value를 수정할 수 있는 것이다
우리는 클래스의 변수에 접근하고 싶은 클래스에서 friend 로 declare 해주면 된다
참고로 파라미터로 전달을 해줘야지 멤버 변수에 접근할 수 있다는 것은 매우 합리적인 생각이다
만약 파라미터로 어떤 객체를 전달 받는지도 모른체로는 member variable에 접근할 수 없을 것이다
여기 another example이 있다
#include <iostream>
class Value
{
private:
int m_value{};
public:
Value(int value)
: m_value{ value }
{
}
friend bool isEqual(const Value& value1, const Value& value2);
};
bool isEqual(const Value& value1, const Value& value2)
{
return (value1.m_value == value2.m_value);
}
int main()
{
Value v1{ 5 };
Value v2{ 6 };
std::cout << std::boolalpha << isEqual(v1, v2);
return 0;
}
위와 같이 복수의 동일 클래스를 받아서 사용하는 것도 가능하다
Multiple friends
함수는 동일 타입의 클래스 뿐만이 아닌 복수의 클래스에서 동시에 friend일 수도 있다
#include <iostream>
class Humidity;
class Temperature
{
private:
int m_temp {};
public:
Temperature(int temp=0)
: m_temp { temp }
{
}
friend void printWeather(const Temperature& temperature, const Humidity& humidity);
};
class Humidity
{
private:
int m_humidity {};
public:
Humidity(int humidity=0)
: m_humidity { humidity }
{
}
friend void printWeather(const Temperature& temperature, const Humidity& humidity);
};
void printWeather(const Temperature& temperature, const Humidity& humidity)
{
std::cout << "The temperature is " << temperature.m_temp <<
" and the humidity is " << humidity.m_humidity << '\n';
}
int main()
{
Humidity hum(10);
Temperature temp(12);
printWeather(temp, hum);
return 0;
}
위 코드에서 주목할 점은 both class에서 frien라고 선언되어야 하고
양쪽 클래스를 언급해야 하므로 forward declaration으로 Humidity 클래스를
forward decl하고 있다
또한 클래스는 return type이 존재하지 않기에 간단히 class ClassName;으로 선언하는 것을 알 수 있다
Friend classes
추가적으로 클래스 전체를 다른 클래스의 friend로 선언하는 것도 가능하다
exmaple:
#include <iostream>
class Storage
{
private:
int m_nValue {};
double m_dValue {};
public:
Storage(int nValue, double dValue)
: m_nValue { nValue }, m_dValue { dValue }
{
}
// Make the Display class a friend of Storage
friend class Display;
};
class Display
{
private:
bool m_displayIntFirst;
public:
Display(bool displayIntFirst)
: m_displayIntFirst { displayIntFirst }
{
}
void displayItem(const Storage& storage)
{
if (m_displayIntFirst)
std::cout << storage.m_nValue << ' ' << storage.m_dValue << '\n';
else // display double first
std::cout << storage.m_dValue << ' ' << storage.m_nValue << '\n';
}
};
int main()
{
Storage storage(5, 6.7);
Display display(false);
display.displayItem(storage);
return 0;
}
위 코드에서 Storage에 Display가 freind라는 선언을 해주었으므로
Display 클래스에서 Storage의 private member variable을 접근해 사용할 수 있음을 알 수 있다
Friend member functions
전체 클래스를 friend로 하는 것 말고도 다른 클래스의 특정 member function에만
friend 선언을 할 수도 있다
example:
class Display; // forward declaration for class Display
class Storage
{
private:
int m_nValue {};
double m_dValue {};
public:
Storage(int nValue, double dValue)
: m_nValue { nValue }, m_dValue { dValue }
{
}
// Make the Display::displayItem member function a friend of the Storage class
friend void Display::displayItem(const Storage& storage); // error: Storage hasn't seen the full definition of class Display
};
class Display
{
private:
bool m_displayIntFirst {};
public:
Display(bool displayIntFirst)
: m_displayIntFirst { displayIntFirst }
{
}
void displayItem(const Storage& storage)
{
if (m_displayIntFirst)
std::cout << storage.m_nValue << ' ' << storage.m_dValue << '\n';
else // display double first
std::cout << storage.m_dValue << ' ' << storage.m_nValue << '\n';
}
};
위 코드에서 friend void Display::displayItem(const Storage& storage);
와 같이 friend 선언을 해주는 것을 알 수 있다
그런데 위의 코드는 error가 발생한다
왜냐하면 Display 함수가 먼저 정의되지 않았기 때문이다
따라서 순서를 바꿔줘야 한다
class Display
{
private:
bool m_displayIntFirst {};
public:
Display(bool displayIntFirst)
: m_displayIntFirst { displayIntFirst }
{
}
void displayItem(const Storage& storage) // error: compiler doesn't know what a Storage is
{
if (m_displayIntFirst)
std::cout << storage.m_nValue << ' ' << storage.m_dValue << '\n';
else // display double first
std::cout << storage.m_dValue << ' ' << storage.m_nValue << '\n';
}
};
class Storage
{
private:
int m_nValue {};
double m_dValue {};
public:
Storage(int nValue, double dValue)
: m_nValue { nValue }, m_dValue { dValue }
{
}
// Make the Display::displayItem member function a friend of the Storage class
friend void Display::displayItem(const Storage& storage); // okay now
};
이렇게 하면 선언에 대한 문제는 해결할 수 있다
하지만 또 다른 문제가 발생한다
우리가 displayItem 함수에서 storage를 const reference로 받고 있기 때문에
Storage 클래스의 forward declaration이 필요하다
따라서 최종적으로 다음과 같이 작성할 수 있다
#include <iostream>
class Storage; // forward declaration for class Storage
class Display
{
private:
bool m_displayIntFirst {};
public:
Display(bool displayIntFirst)
: m_displayIntFirst { displayIntFirst }
{
}
void displayItem(const Storage& storage); // forward declaration above needed for this declaration line
};
class Storage // full definition of Storage class
{
private:
int m_nValue {};
double m_dValue {};
public:
Storage(int nValue, double dValue)
: m_nValue { nValue }, m_dValue { dValue }
{
}
// Make the Display::displayItem member function a friend of the Storage class (requires seeing the full declaration of class Display, as above)
friend void Display::displayItem(const Storage& storage);
};
// Now we can define Display::displayItem, which needs to have seen the full definition of class Storage
void Display::displayItem(const Storage& storage)
{
if (m_displayIntFirst)
std::cout << storage.m_nValue << ' ' << storage.m_dValue << '\n';
else // display double first
std::cout << storage.m_dValue << ' ' << storage.m_nValue << '\n';
}
int main()
{
Storage storage(5, 6.7);
Display display(false);
display.displayItem(storage);
return 0;
}
위의 작업은 매우 번거로워 보인다
하지만 실제로 모두 한파일에서 작업하지 않고 header file cpp file을 나눠서 작업하게 되므로 한결 낫다
Summary
friend 함수 또는 클래스는 마치 해당 클래스의 멤버인 것처럼 다른 클래스의 private 멤버에 액세스할 수 있는 함수 또는 클래스입니다. 이를 통해 friend 함수 또는 friend 클래스는 다른 클래스가 개인 멤버를 노출시키지 않고(예: 액세스 함수를 통해) 다른 클래스와 긴밀하게 작업할 수 있습니다.
Friending은 오버로드된 연산자를 정의할 때 일반적으로 사용되며(나중에 다룰 예정임), 둘 이상의 클래스가 친밀한 방식으로 함께 작업해야 할 때 덜 일반적입니다.
특정 멤버 함수를 friendfh 만들려면 멤버 함수의 클래스에 대한 전체 정의가 먼저 표시되어야 합니다.
Author And Source
이 문제에 관하여(12.15 Friend functions and classes), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@ikmy0ung/12.15-Friend-functions-and-classes저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)