وظائف "الصديق" و << المشغل الزائد: ما هي الطريقة الصحيحة لتحميل المشغل لفصل؟

StackOverflow https://stackoverflow.com/questions/2828280

سؤال

في مشروع أعمل عليه ، لدي ملف Score الفصل ، محدد أدناه في score.h. أحاول أن أفرطها في ذلك ، عندما أ << يتم تنفيذ العملية عليها ، _points + " " + _name طبع.

هذا ما حاولت فعله:

ostream & Score::operator<< (ostream & os, Score right)
{
    os << right.getPoints() << " " << right.scoreGetName();
    return os;
}

فيما يلي الأخطاء التي تم إرجاعها:

score.h(30) : error C2804: binary 'operator <<' has too many parameters

(يظهر هذا الخطأ 4 مرات ، في الواقع)

تمكنت من العمل من خلال إعلان الحمل الزائد كدالة صديق:

friend ostream & operator<< (ostream & os, Score right);

وإزالة Score:: من إعلان الوظيفة في Score.cpp (بفعالية لا تعلن ذلك كعضو).

لماذا هذا العمل ، ومع ذلك فإن القطعة السابقة من الكود لا؟

شكرا على وقتك!

تعديل

لقد قمت بحذف جميع الإشارات إلى الحمل الزائد على ملف الرأس ... ومع ذلك أحصل على الخطأ التالي (والوحيد). binary '<<' : no operator found which takes a right-hand operand of type 'Score' (or there is no acceptable conversion) كيف يأتي اختباري ، في Main () ، لا يمكن العثور على الحمل الزائد المناسب؟ (هذا ليس يشمل ، لقد راجعت)

فيما يلي النتيجة الكاملة

#ifndef SCORE_H_
#define SCORE_H_

#include <string>
#include <iostream>
#include <iostream>

using std::string;
using std::ostream;

class Score
{

public:
    Score(string name);
    Score();
    virtual ~Score();
    void addPoints(int n);
    string scoreGetName() const;
    int getPoints() const;
    void scoreSetName(string name);
    bool operator>(const Score right) const;

private:
    string _name;
    int _points;

};
#endif
هل كانت مفيدة؟

المحلول

ملحوظة: قد ترغب في إلقاء نظرة على المشغل الزائد الأسئلة الشائعة.


يمكن للمشغلين الثنائيين إما أن يكونوا أعضاء في فئة الحجة اليسرى أو وظائفهم المجانية. (يجب أن يكون بعض المشغلين ، مثل المهمة ، أعضاء.) نظرًا لأن الوسيطة اليسرى لمشغلي الدفق هي دفق أو أن يكون مشغلي الدفق إما أعضاء في فئة الدفق أو الوظائف المجانية. الطريقة الكنسية للتنفيذ operator<< لأي نوع هذا:

std::ostream& operator<<(std::ostream& os, const T& obj)
{
   // stream obj's data into os
   return os;
}

لاحظ أنه كذلك ليس وظيفة العضو. لاحظ أيضًا أن الأمر يتطلب الكائن للبث لكل const المرجعي. ذلك لأنك لا ترغب في نسخ الكائن من أجل دفقه ولا تريد تغييره أيضًا.


في بعض الأحيان ، تريد دفق الكائنات التي لا يمكن الوصول إليها الداخلية من خلال الواجهة العامة في صفها ، لذلك لا يمكن للمشغل الحصول عليها. ثم لديك خياران: إما وضع عضو عام في الفصل الذي يقوم بالتدفق

class T {
  public:
    void stream_to(std::ostream&) const {os << obj.data_;}
  private:
    int data_;
};

ودعو ذلك من المشغل:

inline std::ostream& operator<<(std::ostream& os, const T& obj)
{
   obj.stream_to(os);
   return os;
}

أو اجعل المشغل أ friend

class T {
  public:
    friend std::ostream& operator<<(std::ostream&, const T&);
  private:
    int data_;
};

بحيث يمكنه الوصول إلى الأجزاء الخاصة في الفصل:

inline std::ostream& operator<<(std::ostream& os, const T& obj)
{
   os << obj.data_;
   return os;
}

نصائح أخرى

لنفترض أنك تريد كتابة تحميل زائد للمشغل + لذلك يمكنك إضافة اثنين Score كائنات لبعضها البعض ، وآخر حتى تتمكن من إضافة ملف int إلى Score, والثالث حتى تتمكن من إضافة ملف Score إلى int. تلك التي أ Score هي المعلمة الأولى يمكن أن تكون وظائف عضو من الدرجة. لكن الشخص الذي int هي المعلمة الأولى لا يمكن أن تصبح وظائف عضو int, ، حق؟ لمساعدتك في ذلك ، يُسمح لك بكتابة وظائف مجانية. هذا ما يحدث مع هذا << المشغل ، لا يمكنك إضافة وظيفة عضو إلى ostream لذلك تكتب وظيفة مجانية. هذا ما يعنيه ذلك عندما تسلب Score:: جزء.

الآن لماذا يجب أن يكون friend؟ لا. أنت تتصل فقط بالأساليب العامة (getPoints و scoreGetName). ترى الكثير من مشغلي الأصدقاء لأنهم يحبون التحدث مباشرة إلى المتغيرات الخاصة. لا بأس من أن أفعل ذلك ، لأنهم مكتوبون وصيانتهم من قبل الشخص يحافظ على الفصل. فقط لا تحصل على جزء الصديق مع جزء الوظيفة الخالية من الوظائف.

أنت تحصل على أخطاء التجميع عندما operator<< هي وظيفة عضو في المثال لأنك تقوم بإنشاء ملف operator<< هذا يأخذ Score باعتبارها المعلمة الأولى (الكائن يتم استدعاء الطريقة) ، ثم إعطائها معلمة إضافية في النهاية.

عندما تتصل بمشغل ثنائي تم إعلانه كدالة عضو ، فإن الجانب الأيسر من التعبير هو الكائن الذي يتم استدعاء الطريقة. على سبيل المثال a + b قد يعمل مثل هذا:

A a;
B b

a.operator+(b)

من الأفضل عادةً استخدام المشغلين الثنائيين غير الأعضاء (وفي بعض الحالات-على سبيل المثال operator<<ل ostream هي الطريقة الوحيدة للقيام بذلك. في هذه الحالة، a + b قد تعمل هكذا:

A a;
B b

operator+(a, b);

إليك مثالًا كاملاً يوضح كلا الطريقتين للقيام بذلك ؛ Main () سوف يخرج "55" ثلاث مرات:

#include <iostream>

struct B
{
    B(int b) : value(b) {}
    int value;
};


struct A
{
    A(int a) : value(a) {}
    int value;

    int operator+(const B& b) 
    {
        return this->value + b.value;
    }
};

int operator+(const A& a, const B& b)
{
    return a.value + b.value;
}

int main(int argc, char** argv)
{
    A a(22);
    B b(33);

    std::cout << a + b << std::endl;
    std::cout << operator+(a, b) << std::endl;
    std::cout << a.operator+(b) << std::endl;

    return 0;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top