دليل أنماط C ++ من Google. الجزء 2

الجزء 1. مقدمة

الجزء 2. ملفات الرأس

...





عند كتابة التعليمات البرمجية ، نستخدم جميعًا قواعد تنسيق التعليمات البرمجية. في بعض الأحيان يتم اختراع القواعد ، وفي حالات أخرى يتم استخدام أدلة نمطية جاهزة. على الرغم من أن جميع مبرمجي C ++ يقرؤون اللغة الإنجليزية بسهولة أكبر من اللغة الأصلية ، إلا أنه من الأفضل أن يكون لديهم دليل في اللغة الأخيرة.

هذه المقالة هي ترجمة لجزء من دليل أسلوب Google C ++ إلى اللغة الروسية.

المقالة الأصلية (fork on github) ، الترجمة المحدثة .



ملفات الرأس



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



يمكن أن يكون للاستخدام الصحيح لملفات الرأس تأثير كبير على سهولة قراءة التعليمات البرمجية الخاصة بك وحجمها وأدائها.



ستساعدك القواعد التالية على تجنب المشاكل المتكررة مع ملفات الرأس.



ملفات رأس مستقلة



يجب أن تكون ملفات الرأس مكتفية ذاتيًا (من حيث التجميع) ولها امتداد h . يجب أن يكون للملفات الأخرى (غير الرأسية) المراد تضمينها في الكود الامتداد .inc وأن يتم إقرانها بكود التضمين.



يجب أن تكون جميع ملفات الرأس قائمة بذاتها. يجب ألا يعتمد المستخدمون وأدوات التطوير على التبعيات الخاصة عند استخدام ملف الرأس. يجب أن يكون ملف الرأس قابلاً للقفل ويتضمن جميع الملفات الضرورية.



يفضل وضع تعريفات للقوالب والوظائف المضمنة في نفس الملف مع إعلاناتها. ويجب تضمين هذه التعريفات في كل .ccباستخدامها ، وإلا فقد تكون هناك أخطاء في الارتباط في بعض تكوينات الإنشاء. إذا كانت الإعلانات والتعريفات في ملفات مختلفة ، فيجب أن يتضمن أحدهما الآخر. لا تفصل التعريفات في ملفات رأس منفصلة ( -inl.h ). في السابق ، كانت هذه الممارسة شائعة جدًا ، والآن أصبحت غير مرغوب فيها.



كاستثناء ، إذا تم إنشاء جميع المتغيرات المتاحة لوسائط القالب من القالب ، أو إذا كان القالب يطبق الوظائف المستخدمة من قبل فئة واحدة فقط ، فيجوز تعريف القالب في ملف .cc واحد (وواحد فقط) يستخدم فيه هذا القالب.



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



أعد تشغيل القفل



يجب حماية جميع ملفات الرأس #define من إعادة التضمين . يجب أن يكون تنسيق تعريف الماكرو: <PROJECT> _ <PATH> _ <FILE> _H_ .



لضمان التفرد ، استخدم مكونات مسار الملف الكامل في شجرة المشروع. على سبيل المثال ، قد يحتوي الملف foo / src / bar / baz.h في مشروع foo على القفل التالي:



#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_
...
#endif  // FOO_BAR_BAZ_H_


إعلان أولي



إذا أمكن ، لا تستخدم الإعلانات المسبقة. # تضمين ملفات الرأس المطلوبة بدلاً من ذلك .



التعريف

"الإعلان المسبق" هو ​​إعلان عن فئة ، وظيفة ، قالب بدون تعريف مطابق.



لكل



  • . #include ( ) .
  • . #include - .




  • , .
  • API, . , API: , , .
  • std:: .
  • , : #include. , #include ( ) :



          // b.h:
          struct B {};
          struct D : B {};
          // good_user.cc:
          #include "b.h"
          void f(B*);
          void f(void*);
          void test(D* x) { f(x); }  // calls f(B*)
          


    #include B D, test() f(void*).
  • , .
  • يمكن لهيكل الكود الذي يسمح بالتصريح الأولي (وكذلك استخدام المؤشرات كأعضاء في الفصل) أن يجعل الكود محيرًا وبطيئًا.


حكم



  • حاول تجنب التصريح المسبق للكيانات المعلنة في مشروع آخر.
  • عند استخدام دالة معلنة في ملف رأس ، # تضمين هذا الملف دائمًا .
  • عند استخدام قالب فئة ، من الأفضل تضمين ملف الرأس الخاص به.


راجع أيضًا قواعد التضمين في الأسماء وترتيب التضمين .



وظائف مضمنة



قم بتعريف الوظائف كوظائف مضمنة فقط عندما تكون صغيرة ، على سبيل المثال ، لا تزيد عن 10 سطور.



التعريف



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



الايجابيات



يمكن أن يؤدي استخدام وظائف مضمنة إلى إنشاء كود أكثر كفاءة ، خاصة عندما تكون الوظائف صغيرة استخدم هذه الميزة للحصول على / تعيين وظائف ، وظائف أخرى قصيرة وحاسمة للأداء.



ضد



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



الحكم



من القواعد الأساسية الجيدة عدم جعل الوظائف غير قابلة للتثبيت إذا تجاوزت 10 أسطر من التعليمات البرمجية. تجنب جعل المواد المدمرة غير مبطنة منذ ذلك الحين يمكن أن تحتوي ضمنيًا على الكثير من التعليمات البرمجية الإضافية: استدعاء المدمرات المتغيرة والفئات الأساسية!



قاعدة أخرى جيدة هي أنه عادة لا يكون من المنطقي أن تكون الدوال المضمنة التي تحتوي على حلقات أو عبارات تبديل (باستثناء الحالات المتدهورة حيث لا يتم تنفيذ الحلقة أو العبارات الأخرى).



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



الأسماء وتضمين الترتيب



أدخل ملفات الرأس بالترتيب التالي: ملف مزدوج (على سبيل المثال ، foo.h - foo.cc) ، ملفات نظام C ، مكتبة C ++ القياسية ، مكتبات أخرى ، ملفات مشروعك.



يجب أن تكون جميع رؤوس المشروع مرتبطة بدليل مصدر المشروع بدون استخدام أسماء مستعارة لـ UNIX مثل . (الدليل الحالي) أو .. (الدليل الأصل). على سبيل المثال ، يجب تضمين google-awesome-project / src / base / logging.h على النحو التالي:



#include "base/logging.h"


مثال آخر: إذا كانت الوظيفة الرئيسية لملفات dir / foo.cc و dir / foo_test.cc هي تنفيذ واختبار الكود المعلن في dir2 / foo2.h ، فاكتب ملفات الرأس بالترتيب التالي:



  1. dir2 / foo2.h .
  2. C (: .h), <unistd.h>, <stdlib.h>.
  3. C++ ( ), <algorithm>, <cstddef>.
  4. .h .
  5. .h .


افصل بين كل مجموعة (غير فارغة) من الملفات بسطر فارغ.



يسمح لك ترتيب الملفات هذا باكتشاف الأخطاء عندما تكون ملفات الرأس المطلوبة (النظام ، إلخ) مفقودة في ملف الرأس المقترن ( dir2 / foo2.h ) وسيفشل تجميع ملفات dir / foo.cc أو dir / foo_test.cc المقابلة . نتيجة لذلك ، سيظهر الخطأ على الفور للمطور الذي يعمل مع هذه الملفات (وليس لفريق آخر يستخدم مكتبة خارجية فقط).



عادةً ما تكون الملفات المقترنة dir / foo.cc و dir2 / foo2.h في نفس الدليل (على سبيل المثال ، base / basictypes_test.cc و base / basictypes.h ) ، على الرغم من أن هذا ليس مطلوبًا.



لاحظ أن ملفات رأس C مثل stddef.h قابلة للتبديل عادةً مع ملفات C ++ المقابلة ( cstddef ). يمكن استخدام أي اختلاف ، ولكن من الأفضل اتباع نمط الكود الحالي.



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



يجب تضمين جميع ملفات الرأس التي تعلن عن الأنواع التي تريدها ، باستثناء ما تم الإعلان عنه مسبقًا . إذا كانت التعليمات البرمجية الخاصة بك تستخدم أنواعًا من bar.h ، فلا تعتمد على ملف foo.h آخر لتضمين bar.hويمكنك تقييد نفسك بتضمين foo.h فقط : قم بتضمين bar.h صراحة (ما لم يُذكر صراحة (ربما في الوثائق) أن foo.h سيعطيك أيضًا الأنواع من bar.h ).



على سبيل المثال ، قد تبدو قائمة ملفات الرؤوس في google-awesome-project / src / foo / internal / fooserver.cc كما يلي:



#include "foo/server/fooserver.h"
#include <sys/types.h>
#include <unistd.h>
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/commandlineflags.h"
#include "foo/server/bar.h"


الاستثناءات



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



#include "foo/public/fooserver.h"
#include "base/port.h"  // For LANG_CXX11.
#ifdef LANG_CXX11
#include <initializer_list>
#endif  // LANG_CXX11


ملاحظات:



الصورة مأخوذة من المصدر المفتوح .



All Articles