سؤال

أخبرني أحدهم عن اختلاف أسلوب C++ في فريقهم.لدي وجهة نظري الخاصة حول هذا الموضوع، ولكن سأكون مهتما بها الايجابيات و سلبيات قادمة من الجميع.

لذلك، في حالة وجود خاصية فئة تريد عرضها عبر حرفين، أحدهما للقراءة/الكتابة، والآخر للقراءة فقط (أي.لا توجد طريقة محددة).هناك طريقتان على الأقل للقيام بذلك:

class T ;

class MethodA
{
   public :
      const T & get() const ;
      T & get() ;

      // etc.
} ;

class MethodB
{
   public :
      const T & getAsConst() const ;
      T & get() ;

      // etc.
} ;

ما هي إيجابيات وسلبيات كل طريقة؟

أنا مهتم أكثر بالأسباب الفنية/الدلالية لـ C++، ولكن الأسباب النمطية مرحب بها أيضًا.

لاحظ أن MethodB له عيب فني رئيسي واحد (تلميح:في الكود العام).

هل كانت مفيدة؟

المحلول

حسنًا، لسبب واحد، getAsConst يجب يتم استدعاؤه عندما يكون المؤشر "هذا" ثابتًا - وليس عندما تريد تلقي كائن ثابت.لذا، إلى جانب أية مشكلات أخرى، تمت تسميتها بطريقة خاطئة.(لا يزال بإمكانك تسميتها عندما يكون "هذا" غير ثابت، ولكن هذا ليس هنا ولا هناك.)

بتجاهل ذلك، لن تكسبك getAsConst شيئًا، وتضع عبئًا لا مبرر له على المطور الذي يستخدم الواجهة.بدلاً من مجرد استدعاء "get" ومعرفة أنه يحصل على ما يحتاج إليه، عليه الآن التأكد مما إذا كان يستخدم حاليًا متغير const أم لا، وما إذا كان الكائن الجديد الذي يستولي عليه يحتاج إلى const.وفي وقت لاحق، إذا أصبح كلا العنصرين غير ثابتين بسبب بعض عمليات إعادة البناء، فعليه تبديل مكالمته.

نصائح أخرى

يجب أن تكون لغة C++ قادرة تمامًا على التعامل مع الطريقة (أ) في جميع المواقف تقريبًا.أستخدمه دائمًا ولم أواجه أي مشكلة.

الطريقة B، في رأيي، هي حالة انتهاك لـ OneAndOnlyOnce.والآن عليك معرفة ما إذا كنت تتعامل مع مرجع ثابت لكتابة الكود الذي يتم تجميعه لأول مرة.

أعتقد أن هذا أمر أسلوبي - من الناحية الفنية كلاهما يعمل، ولكن MethodA يجعل المترجم يعمل بجهد أكبر قليلاً.بالنسبة لي، إنه أمر جيد.

أنا شخصياً أفضل الطريقة الأولى، لأنها تجعل الواجهة أكثر اتساقًا.أيضًا، بالنسبة لي، تبدو getAsConst() سخيفة تمامًا مثل getAsInt().

ومن ناحية أخرى، يجب عليك التفكير مرتين قبل إرجاع مرجع غير ثابت أو مؤشر غير ثابت إلى عضو بيانات في صفك.هذه دعوة للأشخاص لاستغلال الأعمال الداخلية لفصلك، والتي من الأفضل أن تكون مخفية.وبعبارة أخرى فإنه يكسر التغليف.سأستخدم get() const وset()، وأرجع مرجعًا غير ثابت فقط إذا لم تكن هناك طريقة أخرى، أو عندما يكون ذلك منطقيًا حقًا، مثل منح حق الوصول للقراءة/الكتابة إلى عنصر في مصفوفة أو مصفوفة.

بالنظر إلى النمط السابق الذي حددته المكتبة القياسية (على سبيل المثال، begin() و begin() const لتسمية مثال واحد فقط)، يجب أن يكون واضحًا أن الطريقة A هي الاختيار الصحيح.أنا أشكك في سلامة الشخص الذي يختار الطريقة ب.

لذلك، النمط الأول هو الأفضل بشكل عام.

نحن نستخدم نوعًا مختلفًا من النمط الثاني قليلًا في قاعدة التعليمات البرمجية التي أعمل عليها حاليًا، لأننا نريد تمييزًا كبيرًا بين الاستخدام الثابت وغير الثابت.

في مثالي المحدد، لدينا getTescellation وgetMutableTescellation.يتم تنفيذه باستخدام مؤشر النسخ عند الكتابة.لأسباب تتعلق بالأداء، نريد استخدام إصدار const حيثما كان ذلك ممكنًا، لذلك نجعل الاسم أقصر، ونجعله اسمًا مختلفًا حتى لا يتسبب الأشخاص في حدوث نسخة عن طريق الخطأ عندما لا يريدون الكتابة على أي حال.

بينما يبدو أن سؤالك يتناول طريقة واحدة فقط، سأكون سعيدًا بتقديم مدخلاتي حول الأسلوب.شخصياً، لأسباب تتعلق بالأسلوب، أفضل الخيار الأول.ستظهر لك معظم IDEs توقيع نوع الوظائف لك.

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

الأول يسمح بإجراء تغييرات على نوع المتغير (سواء كان كذلك const أم لا) دون مزيد من التعديل للكود.بالطبع، هذا يعني أنه لا يوجد إشعار للمطور بأن هذا قد تغير عن المسار المقصود.لذلك، فالأمر يتعلق حقًا بما إذا كنت تقدر القدرة على إعادة البناء بسرعة، أو الحصول على شبكة أمان إضافية.

والثاني هو شيء متعلق بالتدوين المجري وأنا شخصياً لا مثل ذلك سألتزم مع أولاً طريقة.

لا أحب التدوين المجري لأنه يضيف التكرار الذي عادة ما أكرهه في البرمجة.انها مجرد رأيي.

نظرًا لأنك تخفي أسماء الفئات، فقد ينطبق أو لا ينطبق هذا الغذاء للتفكير في الأسلوب:

هل من المنطقي إخبار هذين الكائنين، MethodA وMethodB، بـ "get" أو "getAsConst"؟هل سترسل "get" أو "getAsConst" كرسائل إلى أي من الكائنين؟

بالطريقة التي أراها، كمرسل الرسالة/المستدعي للطريقة، أنت هم الذين يحصلون على القيمة؛لذلك ردًا على رسالة "الحصول على" هذه، فإنك ترسل بعض الرسائل إلى MethodA/MethodB، والنتيجة هي القيمة التي تحتاج إلى الحصول عليها.

مثال:إذا كان المتصل بـ MethodA، على سبيل المثال، خدمة في SOA، وكانت MethodA عبارة عن مستودع، فداخل get_A() الخاص بالخدمة، اتصل بـ MethodA.find_A_by_criteria(...).

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

لنفترض أن T كائن قابل للترتيب (على سبيل المثال، يمكننا مقارنته بكائنات من النوع T مع عامل التشغيل <)، ولنفترض أننا نريد العثور على الحد الأقصى بين اثنين من MethodA (resp.طريقتان ب).

بالنسبة إلى MethodA، كل ما نحتاجه للتشفير هو:

template <typename T>
T & getMax(T & p_oLeft, T & p_oRight)
{
   if(p_oLeft.get() > p_oRight.get())
   {
      return p_oLeft ;
   }
   else
   {
      return p_oRight ;
   }
}

سيعمل هذا الكود مع الكائنات const والكائنات غير const من النوع T:

// Ok
const MethodA oA_C0(), oA_C1() ;
const MethodA & oA_CResult = getMax(oA_C0, oA_C1) ;

// Ok again
MethodA oA_0(), oA_1() ;
MethodA & oA_Result = getMax(oA_0, oA_1) ;

تأتي المشكلة عندما نريد تطبيق هذا الكود السهل على شيء يتبع اتفاقية MethodB:

// NOT Ok
const MethodB oB_C0(), oB_C1() ;
const MethodB & oB_CResult = getMax(oB_C0, oB_C1) ; // Won't compile

// Ok
MethodA oB_0(), oB_1() ;
MethodA & oB_Result = getMax(oB_0, oB_1) ;

لكي يعمل MethodB على كل من الإصدار const وغير const، يجب علينا استخدام getMax المحدد بالفعل، ولكن نضيف إليه الإصدار التالي من getMax:

template <typename T>
const T & getMax(const T & p_oLeft, const T & p_oRight)
{
   if(p_oLeft.getAsConst() > p_oRight.getAsConst())
   {
      return p_oLeft ;
   }
   else
   {
      return p_oRight ;
   }
}

الاستنتاج، من خلال عدم الثقة في المترجم بشأن الاستخدام المستمر، فإننا نثقل كاهل أنفسنا بإنشاء وظيفتين عامتين في حين كان من المفترض أن تكون إحداهما كافية.

بالطبع، مع ما يكفي من جنون العظمة، كان ينبغي أن تسمى وظيفة القالب الثاني getMaxAsConst...وبالتالي فإن المشكلة سوف تنتشر من خلال كل التعليمات البرمجية ...

:-ص

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