Programing

operator <<를 친구 또는 멤버 함수로 구현해야합니까?

lottogame 2020. 7. 17. 08:15
반응형

operator <<를 친구 또는 멤버 함수로 구현해야합니까?


그것은 기본적으로 문제입니다. 구현하는 "올바른"방법이 operator<<있습니까? 이것을 읽으면 다음과 같은 것을 볼 수 있습니다.

friend bool operator<<(obj const& lhs, obj const& rhs);

같은 것보다 선호

ostream& operator<<(obj const& rhs);

그러나 왜 하나를 사용 해야하는지 알 수 없습니다.

내 개인적인 경우는 다음과 같습니다

friend ostream & operator<<(ostream &os, const Paragraph& p) {
    return os << p.to_str();
}

그러나 나는 아마 할 수있다 :

ostream & operator<<(ostream &os) {
    return os << paragraph;
}

이 결정의 근거는 무엇입니까?

참고 :

 Paragraph::to_str = (return paragraph) 

단락은 문자열입니다.


여기서 문제는 귀하가 링크 한 기사를 해석하는 데 있습니다 .

이 기사는 부울 관계 연산자를 올바르게 정의하는 데 문제가있는 사람에 관한 것입니다.

운영자 :

  • 평등 == 및! =
  • 관계 <> <=> =

이 연산자는 같은 유형의 두 객체를 비교할 때 부울을 반환해야합니다. 일반적으로 이러한 연산자를 클래스의 일부로 정의하는 것이 가장 쉽습니다. 이것은 클래스가 자동으로 자신의 친구이므로 단락 유형의 객체는 서로를 검사 할 수 있기 때문입니다 (서로도 다른 개인 멤버).

이 독립형 함수를 만드는 데에는 논쟁의 여지가 있습니다. 이렇게하면 같은 형식이 아닌 경우 자동 변환으로 양쪽을 변환 할 수 있고 멤버 함수에서는 rhs 만 자동 변환 할 수 있습니다. 나는 당신이 실제로 자동 변환이 처음부터 일어나기를 원하지 않기 때문에 이것이 종이 남자 논쟁이라고 생각합니다. 그러나 이것이 당신이 원하는 것이라면 (권장하지 않습니다) 비교기를 자유롭게 세우는 것이 유리 할 수 ​​있습니다.

스트림 연산자 :

  • 연산자 << 출력
  • 연산자 >> 입력

이진 시프트 대신 스트림 연산자로이를 사용할 때 첫 번째 매개 변수는 스트림입니다. 스트림 객체에 액세스 할 수 없기 때문에 (수정 할 객체는 아님) 멤버 연산자가 될 수 없으며 클래스 외부에 있어야합니다. 따라서 학생들은 수업의 친구이거나 스트리밍을 수행 할 공개 메소드에 액세스 할 수 있어야합니다.

또한 이러한 객체는 스트림 객체에 대한 참조를 반환하여 스트림 작업을 함께 연결할 수있는 것이 일반적입니다.

#include <iostream>

class Paragraph
{
    public:
        explicit Paragraph(std::string const& init)
            :m_para(init)
        {}

        std::string const&  to_str() const
        {
            return m_para;
        }

        bool operator==(Paragraph const& rhs) const
        {
            return m_para == rhs.m_para;
        }
        bool operator!=(Paragraph const& rhs) const
        {
            // Define != operator in terms of the == operator
            return !(this->operator==(rhs));
        }
        bool operator<(Paragraph const& rhs) const
        {
            return  m_para < rhs.m_para;
        }
    private:
        friend std::ostream & operator<<(std::ostream &os, const Paragraph& p);
        std::string     m_para;
};

std::ostream & operator<<(std::ostream &os, const Paragraph& p)
{
    return os << p.to_str();
}


int main()
{
    Paragraph   p("Plop");
    Paragraph   q(p);

    std::cout << p << std::endl << (p == q) << std::endl;
}

암시 적 this매개 변수는 <<-operator 의 왼쪽 이므로 멤버 함수로 수행 할 수 없습니다 . (따라서 ostream-class에 멤버 함수로 추가해야합니다 . 좋지 않음 :)

당신이 그것을하지 않고 무료 기능으로 할 수 friend있습니까? 이것이 내가 선호하는 것입니다. 이것이 ostream클래스의 핵심 기능이 아니라 와의 통합임을 분명히하기 때문 입니다.


가능하면 비회원 및 비 친구 기능.

Herb Sutter와 Scott Meyers가 설명했듯이 캡슐화를 높이기 위해 비 친구 비회원 기능을 회원 기능보다 선호합니다.

C ++ 스트림과 같은 일부 경우에는 선택 사항이 없으며 멤버가 아닌 함수를 사용해야합니다.

그러나 여전히 그렇다고해서 이러한 함수를 클래스의 친구로 만들어야한다는 의미는 아닙니다. 이러한 함수는 여전히 클래스 접근자를 통해 클래스에 액세스 할 수 있습니다. 이러한 방식으로 이러한 기능을 작성하면 성공합니다.

연산자 << 및 >> 프로토 타입 정보

귀하의 질문에 제시 한 예가 잘못되었다고 생각합니다. 예를 들어;

ostream & operator<<(ostream &os) {
    return os << paragraph;
}

이 방법이 스트림에서 어떻게 작동하는지 생각조차 할 수조차 없습니다.

<< 및 >> 연산자를 구현하는 두 가지 방법은 다음과 같습니다.

T 유형의 스트림과 같은 객체를 사용한다고 가정 해 봅시다.

그리고 단락 유형의 객체의 관련 데이터를 추출 / 삽입하려고합니다.

일반 연산자 << 및 >> 함수 프로토 타입

첫 번째는 함수입니다.

// T << Paragraph
T & operator << (T & p_oOutputStream, const Paragraph & p_oParagraph)
{
   // do the insertion of p_oParagraph
   return p_oOutputStream ;
}

// T >> Paragraph
T & operator >> (T & p_oInputStream, const Paragraph & p_oParagraph)
{
   // do the extraction of p_oParagraph
   return p_oInputStream ;
}

일반 연산자 << 및 >> 메서드 프로토 타입

두 번째는 방법입니다.

// T << Paragraph
T & T::operator << (const Paragraph & p_oParagraph)
{
   // do the insertion of p_oParagraph
   return *this ;
}

// T >> Paragraph
T & T::operator >> (const Paragraph & p_oParagraph)
{
   // do the extraction of p_oParagraph
   return *this ;
}

이 표기법을 사용하려면 T의 클래스 선언을 확장해야합니다. STL 객체의 경우 불가능합니다 (수정하지 않아야합니다 ...).

그리고 T가 C ++ 스트림이라면?

다음은 C ++ 스트림에 대해 동일한 << 및 >> 연산자의 프로토 타입입니다.

일반 basic_istream 및 basic_ostream

Note that is case of streams, as you can't modify the C++ stream, you must implement the functions. Which means something like:

// OUTPUT << Paragraph
template <typename charT, typename traits>
std::basic_ostream<charT,traits> & operator << (std::basic_ostream<charT,traits> & p_oOutputStream, const Paragraph & p_oParagraph)
{
   // do the insertion of p_oParagraph
   return p_oOutputStream ;
}

// INPUT >> Paragraph
template <typename charT, typename traits>
std::basic_istream<charT,traits> & operator >> (std::basic_istream<charT,traits> & p_oInputStream, const CMyObject & p_oParagraph)
{
   // do the extract of p_oParagraph
   return p_oInputStream ;
}

For char istream and ostream

The following code will work only for char-based streams.

// OUTPUT << A
std::ostream & operator << (std::ostream & p_oOutputStream, const Paragraph & p_oParagraph)
{
   // do the insertion of p_oParagraph
   return p_oOutputStream ;
}

// INPUT >> A
std::istream & operator >> (std::istream & p_oInputStream, const Paragraph & p_oParagraph)
{
   // do the extract of p_oParagraph
   return p_oInputStream ;
}

Rhys Ulerich commented about the fact the char-based code is but a "specialization" of the generic code above it. Of course, Rhys is right: I don't recommend the use of the char-based example. It is only given here because it's simpler to read. As it is only viable if you only work with char-based streams, you should avoid it on platforms where wchar_t code is common (i.e. on Windows).

Hope this will help.


It should be implemented as a free, non-friend functions, especially if, like most things these days, the output is mainly used for diagnostics and logging. Add const accessors for all the things that need to go into the output, and then have the outputter just call those and do formatting.

I've actually taken to collecting all of these ostream output free functions in an "ostreamhelpers" header and implementation file, it keeps that secondary functionality far away from the real purpose of the classes.


The signature:

bool operator<<(const obj&, const obj&);

Seems rather suspect, this does not fit the stream convention nor the bitwise convention so it looks like a case of operator overloading abuse, operator < should return bool but operator << should probably return something else.

If you meant so say:

ostream& operator<<(ostream&, const obj&); 

Then since you can't add functions to ostream by necessity the function must be a free function, whether it a friend or not depends on what it has to access (if it doesn't need to access private or protected members there's no need to make it friend).


Just for completion sake, I would like to add that you indeed can create an operator ostream& operator << (ostream& os) inside a class and it can work. From what I know it's not a good idea to use it, because it's very convoluted and unintuitive.

Let's assume we have this code:

#include <iostream>
#include <string>

using namespace std;

struct Widget
{
    string name;

    Widget(string _name) : name(_name) {}

    ostream& operator << (ostream& os)
    {
        return os << name;
    }
};

int main()
{
    Widget w1("w1");
    Widget w2("w2");

    // These two won't work
    {
        // Error: operand types are std::ostream << std::ostream
        // cout << w1.operator<<(cout) << '\n';

        // Error: operand types are std::ostream << Widget
        // cout << w1 << '\n';
    }

    // However these two work
    {
        w1 << cout << '\n';

        // Call to w1.operator<<(cout) returns a reference to ostream&
        w2 << w1.operator<<(cout) << '\n';
    }

    return 0;
}

So to sum it up - you can do it, but you most probably shouldn't :)


operator<< implemented as a friend function:

#include <iostream>
#include <string>
using namespace std;

class Samp
{
public:
    int ID;
    string strName; 
    friend std::ostream& operator<<(std::ostream &os, const Samp& obj);
};
 std::ostream& operator<<(std::ostream &os, const Samp& obj)
    {
        os << obj.ID<< “ ” << obj.strName;
        return os;
    }

int main()
{
   Samp obj, obj1;
    obj.ID = 100;
    obj.strName = "Hello";
    obj1=obj;
    cout << obj <<endl<< obj1;

} 

OUTPUT: 100 Hello 100 Hello Press any key to continue…

This can be a friend function only because the object is on the right hand side of operator<< and argument cout is on the left hand side. So this can't be a member function to the class, it can only be a friend function.


friend operator = equal rights as class

friend std::ostream& operator<<(std::ostream& os, const Object& object) {
    os << object._atribute1 << " " << object._atribute2 << " " << atribute._atribute3 << std::endl;
    return os;
}

참고URL : https://stackoverflow.com/questions/236801/should-operator-be-implemented-as-a-friend-or-as-a-member-function

반응형