在閱讀《深刻理解C++11》時對POD的理解有些疑惑,stack overflow上有一篇高分回答寫得很是棒,如今我把它翻譯一遍加深一下本身的理解(原文): ##如何閱讀這篇文章 這篇文章有點長,若是你想同時瞭解aggregates和PODs(Plain Old Date),就請花點時間把這篇文章讀完。若是你僅僅對aggregates感興趣,則只需閱讀第一部分就好。若是你只對PODs感興趣,你必須首先搞清楚aggregates的定義、含義和示例,而後你就能夠跳到PODs部分閱讀,但我依然建議仍是把第一部分閱讀完畢。Aggregates的概念對於定義PODs來講是必不可少的。c++
##什麼是aggregates以及它的特殊性 在C++標準中的正式定義(C++03 8.5.1 §1):數組
Aggregate是一個數組或者是一個沒有用戶定義的構造函數、沒有private和protected的非靜態成員變量、沒有基類和虛函數的類。
讓咱們來解析一下這個定義。首先,任何數組都是一個aggregate類型。一個類若是知足如下條件也能夠是aggregate類型。。。等待,咱們好像忘記說結構體和聯合體,它們能夠成爲aggregate類型嗎?答案是他們也能夠成爲aggregate類型。在C++中,class術語指的是全部的類、結構體和聯合體。因此說,一個類(或者結構體,或者聯合體)知足上述定義的條件時,就是aggregate類型的。這些條件意味着什麼?函數
- 這並不意味着aggregate類不能擁有構造函數,事實上它能夠擁有默認的構造函數和/或賦值構造函數,只要它們是編譯器隱式聲明,而不是用戶顯示聲明;
- 沒有private和protected的非靜態成員變量,你能夠定義不少private和protected的成員函數(構造函數除外)和private和protected的靜態成員變量,這都不違背aggregate的規則;
- aggregate類能夠擁有用戶聲明/用戶定義的賦值操做和/或析構函數;
- 數組都是aggregate類型,即使數組元素是非aggregate類型。 如今讓咱們來看一些例子:
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 };
你已經明白了aggregates的含義。如今讓咱們來看下aggregates有什麼特別之處。與非aggregate類不一樣的是,aggregates類型能夠用{}進行初始化。這種初始化語法一般被用於數組,但咱們如今瞭解到的是aggregates。因此讓咱們先從數組開始:oop
Type array_name[n] = {a1, a2, …, am};
若是 m==n 第i個元素用a<sub>i</sub>初始化; 若是 m<n 前m個元素分別用a<sub>1</sub>、a<sub>2</sub>、a<sub>3</sub>... a<sub>m</sub>;剩餘n-m個元素若是可能的話會用值初始化(後面會解釋這個名詞); 若是 m>n 編譯器將報出一個錯誤; 其他的狀況如a[] = {1,2,3}; 會假設數組(n)的大小爲m,所以int a[] = {1,2,3}; 等同於a[3] = {1,2,3};翻譯
當一個對象是標量類型(bool, int, char, double, 指針等)時,它的值初始化指得是用0進行初始化(bool類型值爲false,double類型值爲0等)。指針
數組初始化的例子:code
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沒有默認構造函數,不能夠用值初始化a2[1]和a2[2] B b1[3] = {B()}; //OK, b1[1] and b1[2]用值初始化,在這個例子中用的默認構造函數 int Array1[1000] = {0}; //全部的元素都被初始化爲0 int Array2[1000] = {1}; //只有第1個元素初始化爲1,其他的元素都初始化爲0 bool Array3[1000] = {}; //大括號能夠爲空,全部元素初始化爲false int Array4[1000]; //沒有初始化,這和空初始化{}不一樣 //在這個例子中元素沒有值初始化,擁有不肯定的值 //(除非Array4是一個全局數組) int array[2] = {1, 2, 3, 4}; //ERROR,太多元素被初始化 }
如今讓咱們看下如何使用打括號初始化aggregates類。與上述大體相同。咱們將按照非靜態數據成員在類定義中的出現順序初始化它們,而不是數組元素(根據定義,它們都是公共的)。若是須要初始化的比成員變量少,那麼其餘元素都是進行值初始化。若是沒法對未進行顯式初始化的某個成員變量進行值初始化,則在編譯時會遇到錯誤。若是初始化成員變量的數量超過所需的數量,咱們仍是會在編譯的時候遇到錯誤。對象
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}};
在上述例子中y.c
被初始化爲'a'
,y.x.i1
爲10
,y.x.i2
爲20
,y.i[0]
爲20
,y.i[1]
爲30
,y.f
則被值初始化,即被初始化爲0.0
。protected的static類型的成員變量沒有被初始化。ci
Aggregate聯合體則不一樣,只有第一個成員變量能夠用大括號進行初始化。我認爲,若是您在c++方面高級到能夠考慮使用union(它們的使用可能很是危險,必須仔細考慮)的地步,那麼您能夠本身在標準中查找union的規則:-)。rem
如今咱們已經知道了aggregates類型的特殊之處,如今咱們嘗試理解一下它對類型的限制,也就是說爲何會有這些限制。咱們應該理解,帶大括號的成員初始化意味着類只不過是其成員變量的集合。若是用戶定義了構造函數,這意味着徐虎鬚要在初始化成員變量時須要作額外的工做,因此使用大括號初始化會出錯。若是存在虛函數,則意味着該類的對象有一個叫作虛函數表的指針(在大多數實現當中),該指針會在構造函數中進行設置,所以使用大括號初始化是不夠的。做爲練習,你能夠用這種方法理解其餘條件限制的含義:-)。
未完待續。。。