لا يتم استدعاء المشغل المحمّل الزائد في C ++
-
20-09-2019 - |
سؤال
أنا أكتب مكتبة الرياضيات كتمرين عملي. لقد واجهت بعض المشكلات عند زيادة التحميل = المشغل. عندما قمت بتصحيحها ، لاحظت أن المكالمة إلى Vertex1 = Vertex2 تستدعي مُنشئ النسخ بدلاً من ذلك.
في ملف الرأس لدي:
//constructors
vector3();
vector3( vector3 &v );
vector3(float ix, float iy, float iz);
//operator overloading
vector3 operator =(vector3 p);
....
في الملف المصدر الذي قمت بتطبيقه:
vector3 vector3::operator =(vector3 p)
{
vector3 v3;
v3.x = p.x;
v3.y = p.y;
v3.z = p.z;
return v3;
}
في وقت لاحق ، لدي طريقة متقاطعة ، وأريد استخدامها مثل ذلك:
vector3 v3;
v3 = v1.crossProduct(v2);
رسالة الخطأ هي: خطأ: لا توجد وظيفة مطابقة للاتصال بـ "Vector3 :: Vector3 (Vector3)" لكنني لا أريد الاتصال بمنشئ النسخ.
المحلول
هناك أخطاء في الكود الخاص بك. يجب أن يأخذ بنية النسخ الخاصة بك ملف const&
. ستتجنب المرجع إنشاء نسخة (لن تكون قادرًا على القيام بها ، كونها بنية النسخ) ، وينبغي أن تكون const
بما أنك لا تعدله:
vector3(const vector3&);
يمكن ربط المتغيرات المؤقتة const&
, ، لكن لا تستطيع تكون ملزمة لمرجع قابل للتغيير. هذا هو ، مع الكود الخاص بك يمكنك القيام به:
vector3 a;
vector3 b(a);
لكن لا:
vector3 a(some_calculation()); // some_calculation returns a vector3
بالإضافة إلى ذلك ، الخاص بك operator=
غير صحيح. مثل البناء البني ، يجب أن يستغرق عمومًا ملف const&
, ولكن يجب أن يعيد إشارة إلى this
. هذه هي الطريقة التي يعمل بها التسلسل:
int a, b, c;
a = b = c = 0;
// a.operator=(b.operator=(c.operator=(0)));
إن العودة المؤقتة غير تقليدية ، ولا تنجز أي شيء. في حالتك ، يمكنك تعيين مرارا وتكرارا وعدم تغيير القيمة. عجيب:
vector 3 a, b;
a = b; // doesn't change a...?!
operator=
يحتاج إلى التغيير this
.
نصائح أخرى
Vector3 (Vector3 & v) ؛
يجب أن يكون هذا حقا vector3( const vector3 &v );
نظرًا لأن إرجاع قيمة مؤقتة ، يجب عليك الاتصال ببناء نسخ يأخذ مرجعًا const.
لا أريد الاتصال بمنشئ النسخ.
ما تريده غير ذي صلة. أنت بحاجة إلى منشئ نسخة هنا. operator =
لا يتم استدعاؤه في هذا الموقف ، منشئ النسخ هو. علاوة على ذلك ، فإن التوقيع خاطئ ، يجب أن يكون
vector3& operator =(vector3 const& other);
يمكن أيضًا تمرير الحجة بالقيمة (ولكن هذه خدعة متقدمة ...) ولكن قيمة الإرجاع حقًا يجب يكون مرجعا غير مؤشر.
(توقيع مُنشئ النسخ الخاص بك غير تقليدي أيضًا ، انظر إجابة جيمس.)
يجعلون vector3 vector3::operator =(vector3 p)
استخدم المراجع بدلاً من ذلك حتى لا تحتاج إلى إنشاء نسخة.
vector3& vector3::operator =(vector3& p);
لم ترغب في إنشاء كائن نسخ في المقام الأول على أي حال.
من الممارسات الجيدة في C ++ القيام بأحد أمرين اعتمادًا على ما إذا كنت تريد نسخ كائنك (أي يمكن تعيينه لمتغير آخر) أم لا. إذا كنت بحاجة إلى توفير كل من مشغل تعيين ومُنشئ النسخ. فمثلا:
class Point
{
public:
Point () { }
Point (int x, int y) : mX(x), mY(y) { }
Point (const Point& p) : mX(p.mX), mY(p,mY) { }
Point& operator = (const Point& p) { mX = p.mX; mY = p.mY; return *this; }
int X () const { return mX; }
int Y () const { return mY; }
private:
int mX;
int mY;
};
إذا كنت لا ترغب في نسخها ، فيمكنك وضع النموذج الأولي لكل من مُنشئ النسخ ومشغل تعيين في قسم خاص ولا توفر تنفيذًا. أي محاولة لنسخها ثم ستعطي خطأ المترجم.
كلما استخدمت هذا النوع من التعليمات البرمجية:
Point P = anotherP;
سيتم استدعاء مُنشئ النسخ. إذا كنت تستخدم هذا النوع من التعليمات البرمجية:
Point P;
P = anotherP;
سيتم استدعاء عامل تعيين.
امل ان يساعد.
عندما "تمر حسب القيمة" ، كما أنت في تعريفك للمشغل = ، يتم إجراء نسخة من النوع لاستخدام قيمة محلية للطريقة. لا يتم استدعاء المشغل الخاص بك لأن النظام لا يمكنه العثور على مفصل يأخذ Vector3 - لقد حددت منشئ نسخ يأخذ Vector3 &.
لذلك ، كما ذكر الآخرون ، فإن ما تريد القيام به هو تحديد مشغلك = على أنه أخذ
const vector3& p
يجب عليك أيضًا تحديث مُنشئ النسخ المعلن عن أخذ Const Vector3 أيضًا.