مهمة الأعضاء في وظيفة const
-
22-09-2019 - |
سؤال
لدي عضو في الفصل عضو هذا هو نوعي مؤشر. أريد تعيين هذا العضو في وظيفة تم إعلانها باسم const. أنا أفعل على النحو التالي:
void func() const
{
...
const_cast<myType*>(myMember) = new myType();
...
}
يعمل هذا بشكل جيد في VC ++ ، لكن GCC يعطي خطأً في الرسالة "LVALUE مطلوب كمعامل رئيسي من المهمة".
جعل العضو متقلب اسمح لي ببساطة بإزالة const_cast وتعيين القيمة. ومع ذلك ، لست متأكدًا تمامًا من أن ذلك يأتي مع آثار جانبية أخرى.
هل يمكنني تعيين عضوي دون الحاجة إلى جعل العضو قابلاً للتغيير؟ كيف؟ هل هناك أي آثار جانبية في جعل الأعضاء قابلة للتغيير؟
المحلول
لن يعمل الكود فعليًا في VC ++ - أنت لا تقوم بتحديث القيمة (أو على الأقل لا ينبغي) ، وبالتالي التحذير من GCC. الكود الصحيح هو
const_cast<myType*&>(myMember) = new myType();
أو [من الرد الآخر ، شكرًا: P]:
const_cast<ThisType*>(this)->myMember = new myType();
مما يجعلها قابلة للتغيير بشكل فعال أنك تصبح ضمنيًا const_cast
S في const
وظائف الأعضاء ، وهو ما يجب أن توجه إليه بشكل عام عندما تجد نفسك تقوم بأحمال const_cast
S على this
. لا توجد "آثار جانبية لاستخدام قابلة للتغيير" بخلاف ذلك.
كما ترون من المناقشات الشديدة التي تدور حول هذا السؤال ، فإن الاستخدام اللطيف mutable
والكثير من const_cast
يمكن أن تكون S بالتأكيد أعراض رائحة سيئة في الكود الخاص بك. من وجهة نظر مفاهيمية أو إبعاد القدة أو استخدامها mutable
يمكن أن يكون لها آثار أكبر بكثير. في بعض الحالات ، قد يكون الشيء الصحيح الذي يجب القيام به هو تغيير الطريقة إلى غير المحتملين ، أي امتلاك حقيقة أنها تعدل الحالة.
كل هذا يتوقف على مقدار التصحيح الذي يهم في سياقك - أنت لا تريد أن ينتهي الأمر فقط mutable
حول مثل غبار بيكسي لجعل الأشياء تعمل ، ولكن mutable
مخصص للاستخدام إذا لم يكن العضو جزءًا من الحالة الملحوظة للكائن. من شأن الرؤية الأكثر صرامة للتصحيح إلى أنه لا يمكن تعديل جزء واحد من حالة الكائن (على سبيل المثال ، قد يكون هذا أمرًا بالغ الأهمية إذا كنت مثيلًا في ROM ...) - في تلك الحالات ، لا تريد أي قوى لتكون ضائعا. في حالات أخرى ، قد يكون لديك بعض الحالة الخارجية المخزنة في مكان ما من الكائن - على سبيل المثال ، ذاكرة التخزين المؤقت الخاصة بالخيط والتي تحتاج أيضًا إلى أخذها في الاعتبار عند تحديد ما إذا كان مناسبًا.
نصائح أخرى
هذا السيناريو - تغيير الحالة الداخلية المغلفة لا يؤثر على الحالة الخارجية (مثل نتائج التخزين المؤقت) - هو بالضبط ما mutable
الكلمة الرئيسية ل.
const_cast
هو دائما تقريبا علامة على فشل التصميم. في مثالك ، إما func()
لا ينبغي أن يكون const
, ، أو myMember
يجب ان يكون mutable
.
المتصل func()
ستتوقع أن لا يتغير هدفها ؛ لكن هذا يعني "عدم التغيير بطريقة يمكن أن تلاحظها" ؛ هذا ، ليس لتغيير حالته الخارجية. إذا تغير myMember
لا يغير الحالة الخارجية للكائن ، وهذا ما mutable
الكلمة الرئيسية ل ؛ غير ذلك، func()
لا ينبغي أن يكون const
, ، لأنك ستخون ضمانات وظيفتك.
تذكر ذلك mutable
ليست آلية لتصحيح circunvent. إنها آلية لتحسينه.
class Class{
int value;
void func()const{
const_cast<Class*>(this)->value=123;
}
};
كما كتب ستيف جيلهام ، mutable
هو الإجابة الصحيحة (وقصيرة) على سؤالك. أريد فقط أن أعطيك تلميحًا في اتجاه مختلف. ربما يكون من الممكن في Szenario استخدام واجهة (أو أكثر من واحد)؟ ربما يمكنك تجويفه من المثال التالي:
class IRestrictedWriter // may change only some members
{
public:
virtual void func() = 0;
}
class MyClass : virtual public IRestrictedWriter
{
public:
virtual void func()
{
mValueToBeWrittenFromEverybody = 123;
}
void otherFunctionNotAccessibleViaIRestrictedWriter()
{
mOtherValue1 = 123;
mOtherValue2 = 345;
}
...
}
لذا ، إذا انتقلت إلى بعض الوظائف IRestrictedReader *
بدل من const MyClass *
يمكن أن يتصل func
وبالتالي التغيير mValueToBeWrittenFromEverybody
بينما mOtherValue1
هو نوع من "const".
. وجدت mutable
دائما قليلا من الاختراق (ولكن استخدمه في بعض الأحيان).