سؤال

أنا أكتب مكتبة الرياضيات كتمرين عملي. لقد واجهت بعض المشكلات عند زيادة التحميل = المشغل. عندما قمت بتصحيحها ، لاحظت أن المكالمة إلى 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 أيضًا.

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