c++ - لترجمة - قاموس عربي انجليزي ناطق مجاني




ما هي المجاميع و PODs وكيف/لماذا هي خاصة؟ (3)

هل يمكنك رجاء توضيح القواعد التالية:

سأحاول:

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

الأمر بسيط: يجب أن يكون جميع أعضاء البيانات غير الثابتة public أو private أو protected . لا يمكنك الحصول على بعض public وبعض private .

ويعود السبب في ذلك إلى التفكير في التمييز بين "التصميم القياسي" و "ليس التخطيط القياسي" على الإطلاق. أي إعطاء المترجم حرية اختيار كيفية وضع الأشياء في الذاكرة. انها ليست مجرد مؤشرات vtable.

وعندما عادوا إلى توحيد لغة C ++ في عام 98 ، كان عليهم أن يتنبأوا بشكل أساسي بكيفية تنفيذ الناس لها. في حين كان لديهم خبرة في التنفيذ مع النكهات المختلفة من C ++ ، لم يكونوا متأكدين من الأشياء. لذلك قرروا أن يكونوا حذرين: إعطاء المترجمين أكبر قدر ممكن من الحرية.

هذا هو السبب في تعريف POD في C ++ 98 صارمة للغاية. أعطت C ++ compilers خط عرض كبير على تخطيط عضو لمعظم الفئات. في الأساس ، كان المقصود من أنواع POD أن تكون حالات خاصة ، شيء كتبته خصيصا لسبب ما.

عندما كان يعمل على C ++ 11 ، كان لديهم خبرة أكثر بكثير مع المجمعين. وأدركوا أن ... C ++ مترجم الكتاب هم حقا كسول. كان لديهم كل هذه الحرية ، لكنهم لم يفعلوا أي شيء بها.

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

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

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

لذلك لا توجد خسارة كبيرة.

ب) فئة واحدة فقط في شجرة الميراث كلها يمكن أن تحتوي على أعضاء بيانات غير ثابتة ،

يعود سبب هذا إلى سبب توحيد التخطيط القياسي مرة أخرى: ممارسة شائعة.

لا توجد ممارسة شائعة عندما يتعلق الأمر بوجود عضوين من شجرة الميراث التي تخزن الأشياء بالفعل. يضع البعض الطبقة الأساسية قبل المستمدة ، والبعض الآخر يفعل ذلك بالطريقة الأخرى. ما الطريقة التي تطلبها من الأعضاء إذا أتوا من فئتين أساسيتين؟ وما إلى ذلك وهلم جرا. يتباعد المجمّعون بشكل كبير عن هذه الأسئلة.

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

لا يمكنك عمل كل شيء لا يحتوي على وظائف افتراضية وتخطيط افتراضي لمنشئ افتراضي.

ولا يمكن أن يكون عضو البيانات غير ثابت الأول من نوع فئة أساسية (قد يؤدي ذلك إلى فصل قواعد التعرّف).

لا أستطيع حقا التحدث إلى هذا واحد. أنا لست متعلما بما فيه الكفاية في قواعد التعرج C ++ لفهم ذلك حقا. ولكن لها علاقة بحقيقة أن عضو القاعدة سيشترك في نفس العنوان كالطبقة الأساسية نفسها. هذا هو:

struct Base {};
struct Derived : Base { Base b; };

Derived d;
static_cast<Base*>(&d) == &d.b;

وربما هذا هو ضد قواعد التعرج C ++. بطريقة ما.

ومع ذلك ، فكر في هذا: ما مدى فائدة إمكانية امتلاك القدرة على القيام بذلك؟ نظرًا لأن فئة واحدة فقط يمكن أن تحتوي على أعضاء بيانات غير ثابتة ، فيجب أن تكون هذه الفئة Derived (بما أن لها Base كعضو). لذلك يجب أن تكون Base فارغة (من البيانات). وإذا كانت Base فارغة ، فضلا عن فئة أساسية ... لماذا لديك عضو بيانات منه على الإطلاق؟

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

مرة أخرى: لا خسارة كبيرة.

هذه الأسئلة الشائعة حول المجمعات و PODs وتغطي المواد التالية:

  • ما هي الركام ؟
  • ما هي POD s (البيانات القديمة السهلة)؟
  • كيف ترتبط؟
  • كيف ولماذا هي خاصة؟
  • ما هي التغييرات على C ++ 11؟

كيف تقرأ:

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

ما هي المجاميع ولماذا هي خاصة

تعريف رسمي من معيار C ++ ( C ++ 03 8.5.1 §1 ) :

التجميع عبارة عن مصفوفة أو فئة (بند 9) مع عدم وجود مُنشِئين مُعلنين من قِبل المستخدم (12.1) ، ولا يوجد أعضاء بيانات خاصة غير ثابتة أو محمية (المادة 11) ، ولا توجد فصول أساسية (المادة 10) ، ولا توجد وظائف افتراضية (10.3 ).

حسنًا ، حسنًا ، لنحلل هذا التعريف. بادئ ذي بدء ، أي مجموعة هو تجميع. يمكن للفصل أيضًا أن يكون إجماليًا إذا ... انتظر! لا شيء يقال عن البنى أو النقابات ، ألا يمكن أن تكون مجمعة؟ نعم يستطيعون. في C ++ ، يشير المصطلح class إلى كافة الفئات ، والبنيات ، والنقابات. لذا ، فإن الفئة (أو البنية ، أو الاتحاد) هي عبارة عن تجميع إذا وفقت فقط المعايير من التعريفات أعلاه. ماذا تعني هذه المعايير؟

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

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

  • يمكن للفئة التجميعية أن يكون لها مشغل تخصيص / مستخدم محدد من قبل المستخدم و / أو مدمر

  • الصفيف هو تجميع حتى إذا كان مصفوفة من نوع فئة غير مجمعة.

الآن دعونا ننظر إلى بعض الأمثلة:

class NotAggregate1
{
  virtual void f() {} //remember? no virtual functions
};

class NotAggregate2
{
  int x; //x is private by default and non-static 
};

class NotAggregate3
{
public:
  NotAggregate3(int) {} //oops, user-defined constructor
};

class Aggregate1
{
public:
  NotAggregate1 member1;   //ok, public member
  Aggregate1& operator=(Aggregate1 const & rhs) {/* */} //ok, copy-assignment  
private:
  void f() {} // ok, just a private function
};

انت وجدت الفكرة. الآن دعونا نرى كيف أن المجاميع الخاصة. ويمكن ، بخلاف الفصول غير المجمعة ، أن تتم التهيئة باستخدام الأقواس المعقوفة {} . تُعرف بنية التهيئة هذه عمومًا بالصفائف ، وقد علمنا للتو أن هذه التجميعات هي مجاميع. لذا ، دعونا نبدأ بها.

Type array_name[n] = {a 1 , a 2 , …, a m };

إذا (m == n)
تتم تهيئة العنصر الأول من المصفوفة باستخدام حرف i
آخر إذا (م <ن)
تتم تهيئة عناصر m الأولى من المصفوفة مع 1 ، a 2 ،…، m و n - m الأخرى هي ، إذا أمكن ، قيمة التهيئة (انظر أدناه للحصول على شرح المصطلح)
آخر إذا (م> ن)
سيصدر المجمع خطأ
آخر (هذه هي الحالة عندما لا يتم تحديد n على الإطلاق مثل int a[] = {1, 2, 3}; )
يفترض أن حجم المصفوفة (n) مساويًا للقيمة m ، لذلك int a[] = {1, 2, 3}; تعادل int a[3] = {1, 2, 3};

عندما يكون كائن من النوع القياسي ( bool ، int ، char ، double ، pointers، etc.) يتم تهيئته بالقيمة ، يعني أنه تمت تهيئته بـ 0 لهذا النوع ( false لـ bool ، 0.0 لـ double ، إلخ). عندما يتم تهيئة كائن من نوع الفئة مع مُنشئ افتراضي مُعلِن من قِبل المستخدم ، يتم استدعاء مُنشئه الافتراضي. إذا تم تعريف المُنشئ الافتراضي ضمنيًا ، فسيتم أيضًا تهيئة كل العناصر غير الساكنة بشكل تكراري بقيمة. هذا التعريف غير دقيق وغير صحيح بعض الشيء ولكن يجب أن يعطيك الفكرة الأساسية. لا يمكن تهيئة القيمة كمرجع. يمكن أن تفشل عملية تهيئة القيمة لفئة غير مجمعة إذا لم يكن للفئة ، على سبيل المثال ، مُنشئ افتراضي مناسب.

أمثلة على تهيئة المصفوفة:

class A
{
public:
  A(int) {} //no default constructor
};
class B
{
public:
  B() {} //default constructor available
};
int main()
{
  A a1[3] = {A(2), A(1), A(14)}; //OK n == m
  A a2[3] = {A(2)}; //ERROR A has no default constructor. Unable to value-initialize a2[1] and a2[2]
  B b1[3] = {B()}; //OK b1[1] and b1[2] are value initialized, in this case with the default-ctor
  int Array1[1000] = {0}; //All elements are initialized with 0;
  int Array2[1000] = {1}; //Attention: only the first element is 1, the rest are 0;
  bool Array3[1000] = {}; //the braces can be empty too. All elements initialized with false
  int Array4[1000]; //no initializer. This is different from an empty {} initializer in that
  //the elements in this case are not value-initialized, but have indeterminate values 
  //(unless, of course, Array4 is a global array)
  int array[2] = {1, 2, 3, 4}; //ERROR, too many initializers
}

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

struct X
{
  int i1;
  int i2;
};
struct Y
{
  char c;
  X x;
  int i[2];
  float f; 
protected:
  static double d;
private:
  void g(){}      
}; 

Y y = {'a', {10, 20}, {20, 30}};

في المثال أعلاه ، تتم تهيئة yc yxi1 'a' ، yxi1 مع 10 ، yxi2 مع 20 ، yi[0] مع 20 ، yi[1] مع 30 و yf يتم تهيئتها بقيمة ، والتي يتم تهيئتها بـ 0.0 . لا تتم تهيئة العضو الثابت المحمي d مطلقًا لأنه static .

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

الآن بعد أن عرفنا ما هو خاص حول المجاميع ، دعنا نحاول فهم القيود المفروضة على الدروس ؛ هذا سبب وجودهم هناك. يجب أن نفهم أن التهيئة من جانب الأعضاء مع الأقواس تعني أن الطبقة ليست أكثر من مجموع أعضائها. في حالة وجود مُنشئ مُعرّف من قِبَل المستخدم ، فهذا يعني أن المستخدم يحتاج إلى القيام ببعض الأعمال الإضافية لتهيئة الأعضاء ، وبالتالي ستكون تهيئة التهيئة غير صحيحة. في حالة وجود وظائف ظاهرية ، فهذا يعني أن كائنات هذه الفئة لها (في معظم التطبيقات) مؤشر إلى ما يسمى vtable للفئة ، والذي تم تعيينه في المُنشئ ، لذا ستكون تهيئة الأشرطة غير كافية. يمكنك معرفة بقية القيود بطريقة مماثلة لممارسة :).

بما فيه الكفاية حول المجاميع. الآن يمكننا تحديد مجموعة أكثر صرامة من الأنواع ، إلى الذكاء ، PODs

ما هي PODs ولماذا هي خاصة

تعريف رسمي من معيار C ++ ( C ++ 03 9 §4 ) :

إن بنية POD هي فئة تجميعية لا يوجد بها أعضاء بيانات غير ثابتين من نوع non-POD-struct ، أو non-POD-union (أو مصفوفة من مثل هذه الأنواع) أو مرجع ، وليس لديها عامل تخصيص نسخة محدد من قبل المستخدم ولا يوجد destructor المعرفة من قبل المستخدم. وبالمثل ، فإن POD-union هو اتحاد تجميعي لا يحتوي على أعضاء بيانات غير ثابتين من نوع non-POD-struct أو non-POD-union (أو مصفوفة من مثل هذه الأنواع) أو مرجع ، وليس لديه مشغل تخصيص نسخ محدد من قبل المستخدم ولا destructor المعرفة من قبل المستخدم. فئة POD هي فئة إما POD-struct أو POD-union.

واو ، هذا واحد أكثر صعوبة لتحليل ، أليس كذلك؟ :) دعونا نترك النقابات (على نفس الأسس المذكورة أعلاه) وإعادة صياغة بطريقة أوضح قليلا:

يطلق على فئة تجميعية اسم POD إذا لم يكن لها مشغل تخصيص نسخ ومُعيّن من قبل المستخدم ولا أحد من أعضائه غير الساكنين هو فئة غير POD أو مجموعة من غير POD أو مرجع.

ماذا يعني هذا التعريف؟ (هل أذكر POD لتقف على البيانات القديمة سهل ؟)

  • جميع فئات POD هي مجاميع ، أو ، بعبارة أخرى ، إذا كان الفصل الدراسي غير مجمع ، فمن المؤكد أنه ليس POD
  • يمكن أن تكون الطبقات ، مثلها مثل الهياكل ، PODs على الرغم من أن المصطلح القياسي هو POD-struct لكلتا الحالتين
  • مثلما هو الحال في المجاميع ، لا يهم أي أعضاء ثابتة في الفصل

أمثلة:

struct POD
{
  int x;
  char y;
  void f() {} //no harm if there's a function
  static std::vector<char> v; //static members do not matter
};

struct AggregateButNotPOD1
{
  int x;
  ~AggregateButNotPOD1() {} //user-defined destructor
};

struct AggregateButNotPOD2
{
  AggregateButNotPOD1 arrOfNonPod[3]; //array of non-POD class
};

تسمى POD-classes و POD-unions و أنواع قياسية و صفائف من هذا النوع بشكل جماعي أنواع POD.
PODs خاصة في نواح كثيرة. سوف أقدم بعض الأمثلة فقط.

  • تعتبر دورات POD هي الأقرب إلى C structs. خلافا لهم ، يمكن أن يكون PODs وظائف الأعضاء وأعضاء ثابت التعسفي ، ولكن أيا من هذين لا تغيير تخطيط الذاكرة للكائن. لذا إذا كنت ترغب في كتابة مكتبة ديناميكية محمولة أكثر أو أقل يمكن استخدامها من C وحتى .NET ، فيجب أن تحاول جعل جميع وظائفك المصدرة تأخذ وتعيد المعلمات فقط لأنواع POD.

  • يبدأ عمر الكائنات من نوع فئة غير POD عند انتهاء منشئ انتهاء وينتهي عند انتهاء destructor. بالنسبة لفئات POD ، تبدأ مدة الصلاحية عندما يتم تخزين وحدة تخزين الكائن وينتهي عند تحرير هذا التخزين أو إعادة استخدامه.

  • بالنسبة لكائنات أنواع POD ، فإنه يتم ضمانه من خلال معيار أنه عند وضع محتويات الكائن الخاص بك في صف من char أو unsigned char ، ثم memcpy المحتويات مرة أخرى إلى الكائن الخاص بك ، سيحتفظ الكائن قيمته الأصلية. هل لاحظ أنه لا يوجد مثل هذا الضمان لكائنات أنواع غير POD. أيضا ، يمكنك نسخ كائنات POD بأمان مع memcpy . المثال التالي يفترض أن T هو نوع POD:

    #define N sizeof(T)
    char buf[N];
    T obj; // obj initialized to its original value
    memcpy(buf, &obj, N); // between these two calls to memcpy,
    // obj might be modified
    memcpy(&obj, buf, N); // at this point, each subobject of obj of scalar type
    // holds its original value
    
  • بيان goto. كما تعلم ، فإنه من غير القانوني (يجب أن يصدر المترجم خطأ) لإجراء قفزة عبر goto من نقطة حيث لم يكن هناك بعض المتغير بعد في النطاق الذي يكون فيه بالفعل في النطاق. ينطبق هذا القيد فقط إذا كان المتغير من نوع غير POD. في المثال التالي f() غير صحيح في حين g() بشكل جيد. لاحظ أن مترجم مايكروسوفت هو ليبرالي جدا مع هذه القاعدة - انها مجرد إصدار تحذير في كلتا الحالتين.

    int f()
    {
      struct NonPOD {NonPOD() {}};
      goto label;
      NonPOD x;
    label:
      return 0;
    }
    
    int g()
    {
      struct POD {int i; char c;};
      goto label;
      POD x;
    label:
      return 0;
    }
    
  • يضمن أنه لن يكون هناك الحشو في بداية كائن POD. وبعبارة أخرى ، إذا كان العضو الأول في فئة POD هو من النوع T ، فيمكنك reinterpret_cast بأمان من A* إلى T* والحصول على المؤشر إلى العضو الأول والعكس.

والقائمة تطول وتطول…

استنتاج

من المهم أن تفهم ما هو بالضبط POD لأن العديد من ميزات اللغة ، كما ترى ، تتصرف بشكل مختلف بالنسبة لهم.


ما هي التغييرات على C ++ 11؟

تجمعات

تم تغيير التعريف القياسي للرقم بشكل طفيف ، لكنه لا يزال كما هو تقريبًا:

التجميع عبارة عن مصفوفة أو فئة (بند 9) بدون أدوات إنشاء يتم توفيرها من قِبل المستخدم (12.1) ، ولا يوجد مثبتات على شكل دعامة أو غير مساوية لأعضاء البيانات غير الثابتة (9.2) ، ولا يوجد أعضاء بيانات غير مستقلين خاص أو محمي ( الفقرة 11) ، لا توجد فصول أساسية (المادة 10) ، ولا توجد وظائف افتراضية (10.3).

حسنا ، ما الذي تغير؟

  1. في السابق ، لم يكن للمجموع منشئات معلن عنها من قِبل المستخدم ، ولكن الآن لا يمكن إنشاء منشئات مقدمة من قِبل المستخدم . هناك فرق؟ نعم ، هناك ، لأنه يمكنك الآن الإعلان عن المنشئات وإخفاقها :

    struct Aggregate {
        Aggregate() = default; // asks the compiler to generate the default implementation
    };
    

    لا يزال هذا تجميعًا لأن المُنشئ (أو أي وظيفة عضو خاص) التي تم التعطيل عليها في أول تعريف غير مقدم من قبل المستخدم.

  2. لا يمكن أن يحتوي التجميع حاليًا على أي مُبدِّل للمعاملة الثابتة أو غير متساوية لأعضاء البيانات غير الثابتة. ماذا يعني هذا؟ حسنًا ، يرجع ذلك فقط إلى أنه بفضل هذا المعيار الجديد ، يمكننا تهيئة الأعضاء مباشرة في الفصل الدراسي على النحو التالي:

    struct NotAggregate {
        int x = 5; // valid in C++11
        std::vector<int> s{1,2,3}; // also valid
    };
    

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

لذا ، ما هو المجموع لم يتغير كثيرا على الإطلاق. انها لا تزال هي الفكرة الأساسية نفسها ، وتكييفها مع الميزات الجديدة.

ماذا عن PODS؟

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

فكرة POD هي التقاط اثنين من الخصائص المميزة:

  1. وهو يدعم التهيئة الثابتة ، و
  2. يمنحك تجميع POD في C ++ نفس تخطيط الذاكرة كـ بنية تجميع في C.

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

يقول التعريف الجديد في الأساس أن POD هو فئة تافهة تمامًا ولها مخطط قياسي ، ويجب أن تكون هذه الخاصية متكررة لجميع أعضاء البيانات غير الثابتة:

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

دعونا نذهب على كل من هاتين الخاصيتين بالتفصيل على حدة.

دروس تافهة

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

يحدد المعيار فئة تافهة على النحو التالي:

فئة قابلة للنسخ قابلة للترحيل هي فئة:

- لا يوجد بها منشئات غير تافهة (12.8) ،

- ليس لديه أدوات بناء غير تافهة (12.8) ،

- ليس لديه مشغِّل لتخصيص النسخ غير طفيف (13.5.3 ، 12.8) ،

- ليس لديه مشغِّل إسناد حركة غير طفيف (13.5.3 ، 12.8) ، و

- لديه destructor تافهة (12.4).

فئة تافهة هي فئة تحتوي على منشئ افتراضية تافهة (12.1) وهي قابلة للنسخ بشكل بسيط.

[ ملاحظة: على وجه الخصوص ، لا تحتوي الطبقة القابلة للتنازل أو التافهة على وظائف افتراضية أو فصول أساسية افتراضية. لاحظ مذكرة

إذن ، ما هي كل تلك الأشياء التافهة وغير التافهة؟

يعتبر مُنشئ النسخ / النقل للفئة X تافهاً إذا لم يتم توفيره من قبل المستخدم وإذا كان

- الفئة X ليس لها وظائف افتراضية (10.3) ولا توجد فصول أساسية افتراضية (10.1) ، و

- المنشئ المختار لنسخ / نقل كل عنصر فرعي مباشر من الطبقة الأساسية هو أمر بسيط ، و

- لكل عضو بيانات غير ثابت لـ X يكون من نوع الفئة (أو صفيف منه) ، المنشئ المحدد لنسخ / نقل هذا العضو تافه ؛

خلاف ذلك المنشئ نسخ / نقل غير تافهة.

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

ويتشابه تعريف مشغِّل التخصيصات للنسخ / الحركة التافهة إلى حد كبير ، حيث يستعاض ببساطة عن كلمة "منشئ" بكلمة "عامل التشغيل".

كما أن له مدمر تافه تعريف مماثل ، مع القيد المضاف أنه لا يمكن أن يكون ظاهريًا.

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

فيما يلي بعض الأمثلة لمسح كل شيء:

// empty classes are trivial
struct Trivial1 {};

// all special members are implicit
struct Trivial2 {
    int x;
};

struct Trivial3 : Trivial2 { // base class is trivial
    Trivial3() = default; // not a user-provided ctor
    int y;
};

struct Trivial4 {
public:
    int a;
private: // no restrictions on access modifiers
    int b;
};

struct Trivial5 {
    Trivial1 a;
    Trivial2 b;
    Trivial3 c;
    Trivial4 d;
};

struct Trivial6 {
    Trivial2 a[23];
};

struct Trivial7 {
    Trivial6 c;
    void f(); // it's okay to have non-virtual functions
};

struct Trivial8 {
     int x;
     static NonTrivial1 y; // no restrictions on static members
};

struct Trivial9 {
     Trivial9() = default; // not user-provided
      // a regular constructor is okay because we still have default ctor
     Trivial9(int x) : x(x) {};
     int x;
};

struct NonTrivial1 : Trivial3 {
    virtual void f(); // virtual members make non-trivial ctors
};

struct NonTrivial2 {
    NonTrivial2() : z(42) {} // user-provided ctor
    int z;
};

struct NonTrivial3 {
    NonTrivial3(); // user-provided ctor
    int w;
};
NonTrivial3::NonTrivial3() = default; // defaulted but not on first declaration
                                      // still counts as user-provided
struct NonTrivial5 {
    virtual ~NonTrivial5(); // virtual destructors are not trivial
};

تخطيط قياسي

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

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

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

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

هذه هي الطريقة التي يذهب التعريف في النص القياسي:

فئة التصميم القياسي هي فئة:

- لا يوجد لديه أعضاء بيانات غير ثابت من نوع فئة تخطيط غير قياسي (أو مجموعة من هذه الأنواع) أو مرجع ،

- لا توجد وظائف افتراضية (10.3) ولا توجد فصول أساسية افتراضية (10.1) ،

- له نفس التحكم في الوصول (المادة 11) لجميع أعضاء البيانات غير الثابتة ،

- ليس لديه فصول أساسية غير قياسية - تخطيط ،

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

- لا يوجد لديه فئات أساسية من نفس النوع كأول عضو بيانات غير ثابت.

البنية القياسية للتخطيط هي فئة تخطيط قياسية محددة ببنية class-key أو فئة class-key.

اتحاد التنسيق القياسي هو فئة تخطيط قياسية محددة بنقابة المفتاح.

[ ملاحظة: تعتبر فئات التخطيط القياسي مفيدة للتواصل مع الكود المكتوب بلغات برمجة أخرى. يتم تحديد تخطيطها في 9.2. لاحظ مذكرة

ودعونا نرى بعض الأمثلة.

// empty classes have standard-layout
struct StandardLayout1 {};

struct StandardLayout2 {
    int x;
};

struct StandardLayout3 {
private: // both are private, so it's ok
    int x;
    int y;
};

struct StandardLayout4 : StandardLayout1 {
    int x;
    int y;

    void f(); // perfectly fine to have non-virtual functions
};

struct StandardLayout5 : StandardLayout1 {
    int x;
    StandardLayout1 y; // can have members of base type if they're not the first
};

struct StandardLayout6 : StandardLayout1, StandardLayout5 {
    // can use multiple inheritance as long only
    // one class in the hierarchy has non-static data members
};

struct StandardLayout7 {
    int x;
    int y;
    StandardLayout7(int x, int y) : x(x), y(y) {} // user-provided ctors are ok
};

struct StandardLayout8 {
public:
    StandardLayout8(int x) : x(x) {} // user-provided ctors are ok
// ok to have non-static data members and other members with different access
private:
    int x;
};

struct StandardLayout9 {
    int x;
    static NonStandardLayout1 y; // no restrictions on static members
};

struct NonStandardLayout1 {
    virtual f(); // cannot have virtual functions
};

struct NonStandardLayout2 {
    NonStandardLayout1 X; // has non-standard-layout member
};

struct NonStandardLayout3 : StandardLayout1 {
    StandardLayout1 x; // first member cannot be of the same type as base
};

struct NonStandardLayout4 : StandardLayout3 {
    int z; // more than one class has non-static data members
};

struct NonStandardLayout5 : NonStandardLayout3 {}; // has a non-standard-layout base class

استنتاج

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

تحتوي المكتبة القياسية على سمات لاختبار هذه الخصائص في الرأس <type_traits> :

template <typename T>
struct std::is_pod;
template <typename T>
struct std::is_trivial;
template <typename T>
struct std::is_trivially_copyable;
template <typename T>
struct std::is_standard_layout;




c++11