سؤال

أثناء إعادة هيكلة بعض التعليمات البرمجية القديمة، قمت بتجريد عدد من الطرق العامة التي ينبغي أن تكون في الواقع إحصائيات لأنها أ) لا تعمل على أي بيانات عضو أو تستدعي أي وظائف أعضاء أخرى و ب) لأنها قد تكون مفيدة في مكان آخر.

قادني هذا إلى التفكير في أفضل طريقة لتجميع الوظائف "المساعدة" معًا.تتمثل طريقة Java/C# في استخدام فئة من الوظائف الثابتة مع مُنشئ خاص، على سبيل المثال:

class Helper  
{  
private:  
  Helper() { }
public:  
  static int HelperFunc1();  
  static int HelperFunc2();  
};

ومع ذلك، لكونك لغة C++، يمكنك أيضًا استخدام مساحة الاسم:

namespace Helper  
{  
  int HelperFunc1();  
  int HelperFunc2();  
}

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

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

المحلول

الحمل ليس مشكلة، لكن مساحات الأسماء لها بعض المزايا

  • يمكنك إعادة فتح مساحة اسم في رأس آخر ، وتجميع الأشياء بشكل أكثر منطقية مع الحفاظ على التبعيات المترجمة منخفضة
  • يمكنك استخدام الاسم المستعار لمساحة الاسم لصالحك (تصحيح/إصدار ، مساعدين محددين من النظام الأساسي ، ....)

    على سبيل المثاللقد فعلت أشياء مثل

    namespace LittleEndianHelper {
       void Function();
    }
    namespace BigEndianHelper {
       void Function();
    }
    
    #if powerpc
       namespace Helper = BigEndianHelper;
    #elif intel
       namespace Helper = LittleEndianHelper;
    #endif
    

نصائح أخرى

حالة يمكن للمرء أن يستخدمها class (أو struct) زيادة namespace هو عندما يحتاج المرء إلى نوع، على سبيل المثال:

struct C {
  static int f() { return 33; }
};

namespace N {
  int f() { return 9; }
}

template<typename T>
int foo() {
  return T::f();
}

int main() {
  int ret = foo<C>();
//ret += foo<N>(); // compile error: N is a namespace
  return ret;
}

للإضافة إلى استجابة بيتر الممتازة، هناك ميزة أخرى لمساحات الأسماء وهي أنه يمكنك إعادة توجيه الأشياء التي تضعها في مساحة اسم في مكان آخر، وخاصة البنيات...

//Header a.h
// Lots of big header files, spreading throughout your code
class foo
{
  struct bar {/* ... */);
};

//header b.h
#include a.h // Required, no way around it, pulls in big headers
class b
{
  //...
  DoSomething(foo::bar);
};

ومع مساحات الأسماء ...

//Header a.h
// Big header files
namespace foo
{
  struct bar {/* ... */);
}

//header b.h
// Avoid include, instead forward declare 
//  (can put forward declares in a _fwd.h file)
namespace foo
{
  struct bar;
}

class b
{
  //...
  // note that foo:bar must be passed by reference or pointer
  void DoSomething(const foo::bar & o);
};

يُحدث إعلان Forward فرقًا كبيرًا في أوقات الترجمة بعد تغييرات صغيرة في الرأس بمجرد الانتهاء من مشروع يمتد على مئات الملفات المصدر.

تحرير من بيرسيبال

كانت الإجابة جيدة جدًا بحيث لا يمكن تركها تموت بسبب خطأ في التعداد (انظر التعليقات).لقد استبدلت التعدادات (التي يمكن الإعلان عنها للأمام فقط في C++ 0x، وليس في C++ اليوم) بالبنيات.

الميزة الرئيسية لاستخدام مساحة الاسم هي أنه يمكنك إعادة فتحها وإضافة المزيد من العناصر لاحقًا، ولا يمكنك فعل ذلك مع الفصل الدراسي.وهذا يجعل هذا الأسلوب أفضل للمساعدين المقترنين بشكل غير محكم (على سبيل المثال، يمكن أن يكون لديك مساحة اسم Helpers لمكتبتك بأكملها، مثلما هو الحال مع كل STL الموجودة في ::std)

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

لن يكون لديك أي حمل إضافي لوجودهم في الفصل الدراسي مقابل مساحة الاسم.

توفر مساحات الأسماء ميزة إضافية للبحث عن Koenig.قد يؤدي استخدام الفئات المساعدة إلى جعل التعليمات البرمجية الخاصة بك أكثر تفصيلاً - تحتاج عادةً إلى تضمين اسم الفئة المساعدة في المكالمة.

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

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

تم نسخ/تشذيب/إعادة صياغة جزء من إجابتي من كيف يمكنك استخدام مساحات الأسماء بشكل صحيح في C++؟.

باستخدام "استخدام"

يمكنك استخدام "استخدام" لتجنب تكرار "البادئة" لوظيفة المساعد الخاصة بك.على سبيل المثال:

struct AAA
{
   void makeSomething() ;
} ;

namespace BBB
{
   void makeSomethingElse() ;
}

void willCompile()
{
   AAA::makeSomething() ;
   BBB::makeSomethingElse() ;
}

void willCompileAgain()
{
   using BBB ;

   makeSomethingElse() ; // This will call BBB::makeSomethingElse()
}

void WONT_COMPILE()
{
   using AAA ; // ERROR : Won't compile

   makeSomething() ; // ERROR : Won't compile
}

تكوين مساحة الاسم

مساحات الأسماء هي أكثر من مجرد حزم.يمكن العثور على مثال آخر في "لغة البرمجة C++" لـ Bjarne Stroustrup.

في "الطبعة الخاصة"، في 8.2.8 تكوين مساحة الاسم, فهو يصف كيف يمكنك دمج مساحتي أسماء AAA وBBB في مساحة أخرى تسمى CCC.وهكذا يصبح CCC اسمًا مستعارًا لكل من AAA وBBB:

namespace AAA
{
   void doSomething() ;
}

namespace BBB
{
   void doSomethingElse() ;
}

namespace CCC
{
   using namespace AAA ;
   using namespace BBB ;
}

void doSomethingAgain()
{
   CCC::doSomething() ;
   CCC::doSomethingElse() ;
}

يمكنك أيضًا استيراد رموز محددة من مساحات أسماء مختلفة لإنشاء واجهة مساحة الاسم المخصصة الخاصة بك.لم أجد بعد استخدامًا عمليًا لهذا، لكنه من الناحية النظرية رائع.

أميل إلى استخدام مساحات أسماء مجهولة عند إنشاء وظائف مساعدة.نظرًا لأنه يجب (بشكل عام) أن يتم رؤيتها فقط من خلال الوحدة التي تهتم بها، فهي طريقة جيدة للتحكم في التبعيات.

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