وظائف "الصديق" و << المشغل الزائد: ما هي الطريقة الصحيحة لتحميل المشغل لفصل؟
-
26-09-2019 - |
سؤال
في مشروع أعمل عليه ، لدي ملف 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;
}