অপারেটর << বন্ধু হিসাবে বা সদস্য ফাংশন হিসাবে প্রয়োগ করা উচিত?


129

এটি মূলত প্রশ্ন, বাস্তবায়নের কোনও "সঠিক" উপায় 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) 

যেখানে অনুচ্ছেদে একটি স্ট্রিং।


4
বিটিডাব্লু আপনার সম্ভবত সদস্য ফাংশনের স্বাক্ষরগুলিতে
কনস্ট

4
অপারেটর থেকে বুল ফেরত কেন <<? আপনি কি এটি স্ট্রিম অপারেটর হিসাবে বা বিটওয়াস শিফটের ওভারলোড হিসাবে ব্যবহার করছেন?
মার্টিন ইয়র্ক

উত্তর:


120

সমস্যাটি হ'ল আপনার লিঙ্কটি সংযুক্ত নিবন্ধটি আপনার ব্যাখ্যায় ।

সমতা

এই নিবন্ধটি এমন কেউ সম্পর্কে যাঁকে বুল সম্পর্ক অপারেটরগুলি সঠিকভাবে সংজ্ঞায়িত করতে সমস্যা হচ্ছে।

চালক:

  • সমতা == এবং! =
  • সম্পর্ক <> <=> =

এই অপারেটরদের একটি বিল ফেরত দেওয়া উচিত কারণ তারা একই ধরণের দুটি বস্তুর তুলনা করছে। ক্লাসের অংশ হিসাবে এই অপারেটরগুলি সংজ্ঞায়িত করা সবচেয়ে সহজ। এটি কারণ যে কোনও শ্রেণি স্বয়ংক্রিয়ভাবে নিজের একটি বন্ধু তাই প্যারাগ্রাফ টাইপের বস্তুগুলি একে অপরকে পরীক্ষা করতে পারে (এমনকি একে অপরের ব্যক্তিগত সদস্যও)।

এই নিখরচায় ফাংশনগুলি তৈরি করার পক্ষে একটি যুক্তি রয়েছে কারণ এটি উভয় পক্ষের একই ধরণের না হলে অটো রূপান্তর করতে দেয়, যখন সদস্য ফাংশনগুলি কেবল আরএইচএসকে স্বয়ংক্রিয় রূপান্তর করতে দেয়। আমি এটি একটি পেপার ম্যান আর্গুমেন্ট হিসাবে খুঁজে পেয়েছি কারণ আপনি সত্যই প্রথম স্থানটিতে (সাধারণত) অটো রূপান্তর ঘটতে চান না। তবে এটি যদি আপনি চান এমন কিছু হয় (আমি এটির প্রস্তাব দিই না) তবে তুলনাকারীদের মুক্ত স্থায়ী করা সুবিধাজনক হতে পারে।

স্ট্রিমিং

স্ট্রিম অপারেটরগুলি:

  • অপারেটর << আউটপুট
  • অপারেটর >> ইনপুট

আপনি যখন এগুলিকে স্ট্রিম অপারেটর হিসাবে ব্যবহার করেন (বাইনারি শিফটের পরিবর্তে) প্রথম প্যারামিটারটি একটি স্ট্রিম হয়। যেহেতু আপনার কাছে স্ট্রিম অবজেক্টে অ্যাক্সেস নেই (এটি সংশোধন করা আপনার নয়) এগুলি সদস্য অপারেটর হতে পারবেন না তাদের শ্রেণীর বাহ্যিক হতে হবে। সুতরাং তাদের অবশ্যই ক্লাসের বন্ধু হতে হবে বা কোনও পাবলিক পদ্ধতিতে অ্যাক্সেস থাকতে হবে যা আপনার জন্য স্ট্রিমিং করবে।

এই বিষয়গুলির জন্য কোনও স্ট্রিম অবজেক্টের রেফারেন্স ফিরে পাওয়াও traditionalতিহ্যগত যাতে আপনি এক সাথে স্ট্রিম ক্রিয়াকলাপগুলি চেইন করতে পারেন।

#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;
}

19
কেন operator<< private:?
ম্যাট ক্লার্কসন

47
@ ম্যাট ক্লার্কসন: এটি নয়। এটির কোনও কাজের ফাংশন ঘোষণা এইভাবে শ্রেণীর অংশ নয় এবং এভাবে অ্যাক্সেস স্পেসিফায়ারদের দ্বারা প্রভাবিত হয় না। তারা সাধারণত যে ডেটা অ্যাক্সেস করে থাকে তার পাশে আমি সাধারণত বন্ধু ফাংশন ঘোষণাগুলি রাখি।
মার্টিন ইয়র্ক

12
আপনি যদি ডেটা অ্যাক্সেসের জন্য পাবলিক ফাংশনটি ব্যবহার করেন তবে এটি কেন একটি বন্ধুত্বপূর্ণ ফাংশন হওয়া দরকার? দুঃখিত, যদি প্রশ্নটি বোকা হয়।
সেমিওন ড্যানিলভ

4
@ সিমিয়ান ডানিলভ: আপনি কেন এনক্যাপসুলেশন ভেঙে গেটার যুক্ত করবেন! freiendএনক্যাপসুলেশন না ভেঙে সর্বসাধারণের ইন্টারফেসকে বাড়ানোর উপায় a প্রোগ্রামার্স.স্ট্যাক্কেঞ্জেনজিও
মার্টিন ইয়র্ক

3
@ লোকিস্টারি তবে অবশ্যই এটি_র অপসারণ বা ব্যক্তিগত করার পক্ষে যুক্তি। এটি যেমন দাঁড়িয়েছে, স্ট্রিমিং অপারেটরকে বন্ধু হতে হবে না, কারণ এটি কেবল সর্বজনীন ফাংশন ব্যবহার করে।
ডিফোর্ড

53

আপনি এটি সদস্য ফাংশন হিসাবে করতে পারবেন না, কারণ অন্তর্নিহিত thisপ্যারামিটারটি <<-অপরিধারকের বাম দিকে । (অতএব, আপনাকে এটি ostreamক্লাসে সদস্য ফাংশন হিসাবে যুক্ত করা দরকার good ভাল নয় :)

আপনি এটি নিখরচায় বিনামূল্যে ফাংশন হিসাবে এটি করতে পারেন friend? এটিই আমি পছন্দ করি কারণ এটি স্পষ্ট করে দেয় যে এটি ostreamআপনার শ্রেণীর মূল কার্যকারিতা নয় এবং এটির সাথে একীকরণ is


1
"আপনার শ্রেণীর মূল কার্যকারিতা নয়" " "বন্ধু" এর অর্থ এটাই। যদি এটি মূল কার্যকারিতা হয় তবে এটি ক্লাসে থাকবে, বন্ধু নয়।
xaxxon

1
@ এক্সএক্সক্সন আমার মনে হয় আমার প্রথম বাক্যটি ব্যাখ্যা করে যে কেন এই ক্ষেত্রে সদস্য ফাংশন হিসাবে ফাংশন যুক্ত করা অসম্ভব হবে। একটি friendফাংশন একটি সদস্য ফাংশন হিসেবে একই অধিকার আছে ( এই কি friend, যার মানে) যাতে বর্গ একটি ব্যবহারকারী হিসেবে, আমি আশ্চর্য করতে হবে কেন এটা যে প্রয়োজন হবে। "মূল কার্যকারিতা" শব্দটির সাথে আমি এই পার্থক্যটি তৈরি করার চেষ্টা করছি।
ম্যাগনাস হফ

32

যদি সম্ভব হয় তবে অ-সদস্য এবং অ-বন্ধু ফাংশন হিসাবে।

হার্ব সাটার এবং স্কট মায়ারস বর্ণনা অনুসারে, এনক্যাপসুলেশন বাড়াতে সহায়তার জন্য সদস্য ফাংশনগুলির তুলনায় অ-বন্ধু নন-সদস্য ফাংশনটিকে পছন্দ করুন।

কিছু ক্ষেত্রে, যেমন সি ++ স্ট্রিমগুলির মতো আপনার পছন্দ নেই এবং অবশ্যই সদস্যবিহীন ফাংশন ব্যবহার করতে হবে।

তবে তবুও, এর অর্থ এই নয় যে আপনাকে এই ফাংশনগুলি আপনার ক্লাসের বন্ধু বানিয়ে তুলতে হবে: এই ফাংশনগুলি এখনও আপনার ক্লাস অ্যাক্সেসরগুলির মাধ্যমে আপনার ক্লাসে প্রবেশ করতে পারে। আপনি যদি এইভাবে এই ফাংশনগুলি লিখতে সফল হন তবে আপনি জিতেছেন।

অপারেটর << এবং >> প্রোটোটাইপ সম্পর্কে

আমি বিশ্বাস করি আপনি আপনার প্রশ্নে যে উদাহরণ দিয়েছেন তা ভুল are উদাহরণ স্বরূপ;

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

এমনকি এই পদ্ধতিটি কোনও স্ট্রিমে কীভাবে কাজ করতে পারে তা আমি ভাবতেও শুরু করতে পারি না।

<< এবং >> অপারেটরগুলি প্রয়োগ করার জন্য এখানে দুটি উপায়।

ধরা যাক আপনি টি টাইপের স্ট্রিমের মতো অবজেক্টটি ব্যবহার করতে চান Let's

এবং আপনি যে অনুচ্ছেদে টাইপের আপনার অবজেক্টের প্রাসঙ্গিক ডেটা / টি থেকে / সন্নিবেশ করতে চান।

জেনেরিক অপারেটর << এবং >> ফাংশন প্রোটোটাইপস

প্রথম কাজ হিসাবে:

// 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 ;
}

দ্রষ্টব্য যে এই স্বরলিপিটি ব্যবহার করার জন্য, আপনাকে অবশ্যই টি এর শ্রেণির ঘোষণাটি প্রসারিত করতে হবে। এসটিএল অবজেক্টের জন্য, এটি সম্ভব নয় (আপনার এগুলি সংশোধন করার কথা নয় ...)।

এবং টি যদি একটি সি ++ স্ট্রিম হয়?

C ++ স্ট্রীমের জন্য একই << এবং >> অপারেটরগুলির প্রোটোটাইপগুলি এখানে রয়েছে।

জেনেরিক বেসিক_লিস্টিমে এবং বেসিক_স্ট্রিমে

নোটটি হ'ল স্ট্রিমের ক্ষেত্রে যেমন আপনি সি ++ স্ট্রিমটি পরিবর্তন করতে পারবেন না, আপনাকে অবশ্যই ফাংশনগুলি বাস্তবায়ন করতে হবে। যার অর্থ এরকম কিছু:

// 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 ;
}

চর istream এবং অস্ট্রিমের জন্য

নিম্নলিখিত কোডটি কেবল চর-ভিত্তিক স্ট্রিমগুলির জন্য কাজ করবে।

// 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 ;
}

চর-ভিত্তিক কোডটি এটির উপরে জেনেরিক কোডের একটি "বিশেষীকরণ" হলেও এই বিষয়ে মন্তব্য করেন রাইস ইউরিচ। অবশ্যই, রাইস ঠিক: আমি চর-ভিত্তিক উদাহরণ ব্যবহারের প্রস্তাব দিই না। এটি কেবল এখানে দেওয়া হয়েছে কারণ এটি পড়া সহজ। যেহেতু এটি কেবলমাত্র কার্যকর যদি আপনি কেবল চর-ভিত্তিক স্ট্রিমগুলির সাথে কাজ করেন, আপনার প্ল্যাটফর্মগুলিতে এড়ানো উচিত যেখানে ডাব্লুচার_টি কোডটি সাধারণ (যেমন উইন্ডোজে)।

আশা করি এটি সাহায্য করবে।


আপনার জেনেরিক বেসিক_সামগ্রী এবং বেসিক_স্ট্রিমে টেম্পলেট কোডটি ইতিমধ্যে স্ট্যান্ড :: ostream- এবং std :: istream- নির্দিষ্ট সংস্করণগুলি যেহেতু দ্বিতীয়টি পূর্বের দুটি ব্যবহারের অক্ষরের কেবল ইনস্ট্যান্টেশন হিসাবে আবরণ করে?
Rhys Ulerich

@ রাইস ইউরিচ: অবশ্যই আমি কেবল জেনেরিক, টেম্পলেটড সংস্করণ ব্যবহার করি, যদি কেবল উইন্ডোজে থাকে তবে আপনাকে চর এবং ডাব্লুচিকার_আর কোড উভয়ই সামলানো উচিত। দ্বিতীয় সংস্করণের একমাত্র যোগ্যতাটি প্রথমটির চেয়ে আরও সাধারণ হিসাবে প্রদর্শিত হবে। আমি আমার পোস্টটি সে সম্পর্কে পরিষ্কার করব।
প্যার্সেবল

10

এটি একটি নিখরচায়, বন্ধু-বান্ধব ফাংশন হিসাবে প্রয়োগ করা উচিত, বিশেষত যদি আজকের বেশিরভাগ জিনিসের মতো আউটপুটটি মূলত ডায়াগনস্টিকস এবং লগিংয়ের জন্য ব্যবহৃত হয়। আউটপুটে যেতে হবে এমন সমস্ত জিনিসের জন্য কনস্ট অ্যাকসেসর যুক্ত করুন এবং তারপরে আউটপুটটারটি কেবল তাদের কল করুন এবং ফর্ম্যাটিং করুন।

আমি আসলে এই "ostreamhelpers" শিরোনাম এবং বাস্তবায়ন ফাইলে এই সমস্ত অস্ট্রিম আউটপুট ফ্রি ফাংশন সংগ্রহ করার চেষ্টা করেছি, এটি সেই মাধ্যমিক কার্যকারিতা ক্লাসগুলির আসল উদ্দেশ্য থেকে অনেক দূরে রাখে।


7

স্বাক্ষর:

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

সন্দেহজনক বলে মনে হচ্ছে, এটি streamকনভেনশন বা বিটওয়াইজ কনভেনশন মাপসই করে না তাই এটি অপারেটরকে ওভারলোডিং অপব্যবহারের মতো বলে মনে হয়, operator <ফিরে আসা উচিত boolতবে operator <<সম্ভবত অন্য কোনও কিছু ফিরে আসা উচিত।

যদি আপনি বোঝাতে চান তবে বলুন:

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

তারপরে যেহেতু আপনি ostreamপ্রয়োজনীয়তার সাথে ফাংশনগুলি যুক্ত করতে পারবেন না ফাংশনটি অবশ্যই একটি ফাংশন হতে হবে, এটি friendকী ব্যবহার করতে পারে তার উপর নির্ভর করে না (যদি এটি ব্যক্তিগত বা সুরক্ষিত সদস্যদের অ্যাক্সেস করার প্রয়োজন না হয় তবে এটি করার প্রয়োজন নেই) বন্ধু)।


অর্ডারটি ব্যবহার করার সময় এটির পরিবর্তনের অ্যাক্সেসের ostreamপ্রয়োজন হবে ostream.operator<<(obj&); সুতরাং ফ্রি ফাংশন। অন্যথায় অ্যাক্সেস সামঞ্জস্য করার জন্য ব্যবহারকারীর ধরণের স্টিম টাইপ হওয়া দরকার।
wulgargarpro

2

কেবলমাত্র সমাপ্তির জন্য, আমি যুক্ত করতে চাই যে আপনি প্রকৃতপক্ষে কোনও শ্রেণীর ভিতরে একটি অপারেটর তৈরি করতে পারেন ostream& operator << (ostream& os)এবং এটি কাজ করতে পারে। আমি যা জানি তা থেকে এটি ব্যবহার করা ভাল ধারণা নয়, কারণ এটি অত্যন্ত সংশ্লেষযুক্ত এবং অদম্য।

ধরে নেওয়া যাক আমাদের এই কোডটি রয়েছে:

#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;
}

সুতরাং এটি সংক্ষেপে - আপনি এটি করতে পারেন, তবে আপনার সম্ভবত করা উচিত নয় :)


0

বন্ধু অপারেটর = বর্গ হিসাবে সমান অধিকার

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

0

operator<< বন্ধুর ফাংশন হিসাবে প্রয়োগ করা:

#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;

} 

আউটপুট:
100 হ্যালো
100 হ্যালো

এটি কেবলমাত্র বন্ধুর ফাংশন হতে পারে কারণ অবজেক্টটি ডানদিকে operator<<এবং যুক্তিটি coutবাম দিকে রয়েছে। সুতরাং এটি ক্লাসের সদস্য ফাংশন হতে পারে না, এটি কেবল একটি ফাংশন ফাংশন হতে পারে।


আমি মনে করি না এটি সদস্য মজাদার হিসাবে এটি লেখার একটি উপায় আছে !!
রোহিত ভিপিন ম্যাথিউজ

সব সাহসী কেন। আমাকে এটি সরিয়ে দিন।
সেবাস্তিয়ান মাচ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.