(由于簡(jiǎn)書(shū)目前不支持[toc]無(wú)法快速生成目錄潘飘,所以可能看起來(lái)會(huì)有點(diǎn)長(zhǎng)。)
這篇文章的參考處:
https://stackoverflow.com/questions/4178175/what-are-aggregates-and-pods-and-how-why-are-they-special
概述
本段分三個(gè)部分講掉缺,從最開(kāi)始的C++03一直到目前的C++17卜录。
首先要明白一個(gè)從屬關(guān)系和這兩個(gè)概念的基本:
聚類是PODs的一個(gè)超集,即如果一個(gè)class(在標(biāo)準(zhǔn)中眶明,術(shù)語(yǔ)class代表了class艰毒,struct,union)是PODs搜囱,那么這個(gè)類就必為聚類丑瞧,但是如果一個(gè)class是聚類,這個(gè)class不一定是一個(gè)PODs蜀肘。
那么首先要明白的是绊汹,聚類的一個(gè)最明顯的特性,一個(gè)聚類要求扮宠,其本身實(shí)例的結(jié)構(gòu)和內(nèi)部定義的結(jié)構(gòu)一致西乖,即和C中的struct一樣,其實(shí)實(shí)際上是異常相似坛增,里面的成員是什么获雕,那么相應(yīng)一個(gè)實(shí)例的內(nèi)部構(gòu)造就是這些東西組成的,并且要求以上說(shuō)道的這些成員是語(yǔ)法可見(jiàn)的
開(kāi)始正題:
C++03
一轿偎、
一個(gè)聚類由本身特性可知典鸡,聚類是不可能有多態(tài)的,因?yàn)槿绻嬖诨祷蓿瑒t必須在實(shí)例內(nèi)保留一個(gè)指針指向虛表以確定正確執(zhí)行當(dāng)前實(shí)例動(dòng)態(tài)類型的函數(shù)
二萝玷、
以任意訪問(wèn)限定存在的成員函數(shù),靜態(tài)數(shù)據(jù)成員都是允許的昆婿,因?yàn)橐陨蟽烧卟粫?huì)影響對(duì)象實(shí)例的內(nèi)部結(jié)構(gòu)
三球碉、
聚類不能有用戶定義的任何形式的構(gòu)造函數(shù)(以下統(tǒng)稱構(gòu)造函數(shù)),即移動(dòng)仓蛆,拷貝睁冬,構(gòu)造,等,(下面是C++11的內(nèi)容擴(kuò)展)但是用戶可以顯示指定出來(lái)豆拨,即顯示說(shuō)明構(gòu)造函數(shù)的訪問(wèn)限定(在構(gòu)造函數(shù)后加=default)
以上是PODs和聚類相同的地方直奋。
不同的地方有:
一、
聚類可以有用戶定義的復(fù)制函數(shù)施禾,析構(gòu)函數(shù)
二脚线、
聚類的非靜態(tài)成員可以是非PODs的類型(包括數(shù)組,只要是一個(gè)數(shù)組弥搞,就是一個(gè)聚類)
PODs
一邮绿、
PODs要求,用戶不能自定義復(fù)制函數(shù)攀例,析構(gòu)函數(shù)船逮,并且非靜態(tài)成員成員必須在滿足聚類前提下不能是非PODs類型,以及引用類型
以上是C++03的聚類和POD的定義粤铭,下面來(lái)看一下特點(diǎn)挖胃,示例請(qǐng)?jiān)?a target="_blank" rel="nofollow">https://github.com/KinoluKaslana/CPPLearning/blob/master/Aggregate_and_PODs.cpp中查看
首先是聚類
一、
從數(shù)組說(shuō)起承耿,其初始化可以通過(guò)一個(gè){}進(jìn)行初始化(即進(jìn)行顯式初始化)冠骄,當(dāng)initlizer_list中的數(shù)量等于數(shù)組容量時(shí),將對(duì)其進(jìn)行等值拷貝加袋,如果存在小于的情況凛辣,那么其余沒(méi)有被值包括到的數(shù)據(jù)就會(huì)被按照默認(rèn)的初始化方式進(jìn)行初始化,對(duì)于表兩類型职烧,其會(huì)被初始化為0,對(duì)于成員類元素則是調(diào)用其默認(rèn)構(gòu)造函數(shù)扁誓,但是如果成員是引用,則無(wú)法對(duì)其進(jìn)行默認(rèn)初始化
二蚀之、
對(duì)于其他的聚類也一樣可以通過(guò)一對(duì){}將其成員數(shù)據(jù)直接初始化蝗敢,沒(méi)有被包括的則按照默認(rèn)初始化,如果類數(shù)據(jù)成員和引用不存在直接初始化數(shù)據(jù)(對(duì)于類數(shù)據(jù)則需要傳入相應(yīng)構(gòu)造函數(shù)的數(shù)據(jù)格式)則會(huì)拋出錯(cuò)誤
注意足删,以上顯示初始化并不走任何的構(gòu)造函數(shù)
C++11
C++11較C++03
一寿谴、
對(duì)聚類的變化不大,只是對(duì)C++11中的新特性——在定義時(shí)類成員初始化做了限制失受,當(dāng)一個(gè)類讶泰,存在非靜態(tài)的類內(nèi)成員初始化,那么這個(gè)類就不是一個(gè)聚類
二拂到、
對(duì)描述:不能有用戶聲明的構(gòu)造函數(shù)痪署;改為->不能有用戶提供功能的構(gòu)造函數(shù)
但是對(duì)于POD則進(jìn)行了極大的改動(dòng),并且將其拆為了兩個(gè)更加實(shí)用的兩個(gè)類:
trivial和standard layout
trivial:
要了解這個(gè)類兄旬,就必須了解什么是trivial和non-trivial
如果一個(gè)類型符合以下規(guī)定:
一狼犯、
沒(méi)有用戶提供的析構(gòu),復(fù)制,移動(dòng)構(gòu)造函數(shù)(賦值運(yùn)算符)悯森,允許繼承或被繼承但沒(méi)有虛函數(shù)宋舷,虛基類
二、
對(duì)于所有的數(shù)據(jù)成員呐馆,基類數(shù)據(jù)成員肥缔,作為數(shù)據(jù)成員的數(shù)組的元素類型,必須遞歸的滿足上述條件
三汹来、
對(duì)于構(gòu)造函數(shù),則同樣滿足之前Aggregate的規(guī)則同樣也不能存在非靜態(tài)數(shù)據(jù)成員的花括號(hào)改艇,等號(hào)的初始化收班。
四、
對(duì)于析構(gòu)函數(shù)谒兄,也滿足不能是虛函數(shù)條件
那么這個(gè)類型就是一個(gè)trivial copyable的類型
所有的平凡約定摔桦,均代表,默認(rèn)承疲,即非用戶提供的
注意:
一)
trivially copyable是trivial的超集邻耕,前者不對(duì)默認(rèn)構(gòu)造函數(shù)有要求,后者對(duì)默認(rèn)構(gòu)造函數(shù)有要求燕鸽,但是不對(duì)其他非移動(dòng)兄世,復(fù)制的構(gòu)造之外的構(gòu)造函數(shù)有限制。
二)
對(duì)于standard layout 的類啊研,不對(duì)任何構(gòu)造函數(shù)御滩,析構(gòu)函數(shù),復(fù)制党远、移動(dòng)的構(gòu)造函數(shù)削解,復(fù)制、移動(dòng)的復(fù)制運(yùn)算符做要求沟娱,同時(shí)氛驮,只要求所有的非靜態(tài)數(shù)據(jù)成員不為非standard layout類型,和標(biāo)量類型济似,同時(shí)不能有虛基類矫废,虛函數(shù),多繼承是被允許的碱屁,對(duì)于所有的數(shù)據(jù)成員磷脯,并不做任何訪問(wèn)限制要求,唯一的規(guī)定是所有的數(shù)據(jù)成員必須是同一個(gè)訪問(wèn)限制的娩脾。
注意:
由于trivially copyable是不對(duì)任何默認(rèn)構(gòu)造函數(shù)有要求的赵誓,所以單獨(dú)只能在trivially copyable以及std layout中使用member interlized對(duì)POD系成員進(jìn)行初始化。
C++14
C++14中僅僅對(duì)aggregate做了一個(gè)小修改:
一、
允許使用成員初始化俩功。
那么到現(xiàn)在各部分的定義就為:
aggregate:
一幻枉、
不允許當(dāng)前將被定義為aggregate的類(以下稱之為該類)在任何位置存在任何虛函數(shù)。
二诡蜓、
該類不允許出現(xiàn)非public的非靜態(tài)成員
三熬甫、
成員函數(shù)可以為任意訪問(wèn)限定
四、
不允許有用戶提供的構(gòu)造函數(shù)蔓罚,但是允許有用戶提供的重載賦值運(yùn)算符椿肩,析構(gòu)函數(shù),同樣豺谈,這一條定義也必須符合前幾條的規(guī)定
五郑象、
允許基類,非靜態(tài)數(shù)據(jù)成員為任意類型茬末,即非aggregate的都可以厂榛,并且允許其有成員初始化。
trivial
trivially cpoyable
如果一個(gè)類是trivially copyable的話丽惭,則需要遵守以下規(guī)則:
一击奶、
不允許出現(xiàn)非trivial(即用戶提供的)復(fù)制、移動(dòng)構(gòu)造责掏,重載賦值運(yùn)算符柜砾,析構(gòu)函數(shù)
二、
其可以繼承拷橘,但不允許出現(xiàn)虛基類局义,虛函數(shù)
三
所有的非靜態(tài)數(shù)據(jù)成員,基類必須遞歸滿足上述條件即trivially copyable的
trivial
如果一個(gè)類是trivial的話冗疮,需要遵守以下規(guī)則:
一萄唇、
必須滿足所有的trivially copyable的規(guī)定
二、
默認(rèn)構(gòu)造函數(shù)必須為平凡术幔,即不允許出現(xiàn)成員初始化另萤。
三、
對(duì)所有的trivial成員诅挑,基類四敞,必須遞歸滿足上述兩條。
standard layout
如果一個(gè)類是standard layout的話拔妥,需要遵守以下規(guī)則:
一忿危、
所有的非靜態(tài)數(shù)據(jù)成員必須是同一個(gè)訪問(wèn)限定,并且不能是非standard layout的没龙,同時(shí)第一個(gè)非靜態(tài)數(shù)據(jù)成員不能是基類類型
二铺厨、
不能有虛基類缎玫,虛函數(shù)。
三解滓、
繼承樹(shù)上赃磨,只允許有一成員存在非靜態(tài)數(shù)據(jù)成員
四、
對(duì)于所有基類洼裤,數(shù)據(jù)成員遞歸檢測(cè)上述約定不能存在菱形繼承邻辉。
C++17:
aggregate
一、
在C++14的基礎(chǔ)上腮鞍,允許aggregate存在繼承值骇,但是繼承必須是非虛,非private移国,protected雷客,并不強(qiáng)制要求基類為aggregate
二、
不允許存在繼承構(gòu)造桥狡,explicit的構(gòu)造函數(shù)
三、
如果成員皱卓,基類為非aggregate那么他們?nèi)匀皇莑ist-initialized,此時(shí)調(diào)用的是相應(yīng)參數(shù)的構(gòu)造函數(shù)裹芝,如果不存在,則拋出錯(cuò)誤娜汁。
trivial
trivially copyable:
對(duì)C++14中明確規(guī)定的必須包含非trivial的復(fù)制嫂易,移動(dòng)構(gòu)造,運(yùn)算符重載進(jìn)行重申——一個(gè)要求為trivial的類至少包含一個(gè)為非刪除的其中以上的所有函數(shù)掐禁,并且必須包含一個(gè)trivial的非析構(gòu)函數(shù)怜械,對(duì)于其成員類型,以上函數(shù)被聲明為刪除是會(huì)影響當(dāng)前類的trivially copyable的特性的傅事。
trivial:
同上缕允,在滿足上述trivially copyable的情況下,也必須包含一個(gè)trivial的蹭越,非刪除的默認(rèn)構(gòu)造函數(shù)
standard layout:
C++17對(duì)standard layout的繼承障本,有了更加嚴(yán)格的定義:
一、
當(dāng)存在第一個(gè)數(shù)據(jù)成員為以下類型時(shí)响鹃,其對(duì)應(yīng)的基類類型不能是:
二驾霜、
數(shù)據(jù)成員為X,其不含有非靜態(tài)數(shù)據(jù)成員买置,那么基類類型的限制集為空集
三粪糙、
數(shù)據(jù)成員為X,其中第一個(gè)非靜態(tài)數(shù)據(jù)成員類型為X0(有可能是一個(gè)匿名union)那么此時(shí)基類的限制類型為X0和其X0的元素(如果存在的話)組成
四忿项、
數(shù)據(jù)成員為X蓉冈,X是一個(gè)union城舞,那么基類限制集為X中所有的類型,并且對(duì)其union的類型的成員進(jìn)行遞歸本定義的所有條款洒擦。
五椿争、
數(shù)據(jù)成員為X,X是類型為X1的數(shù)組那么集合為X1和X1的類型集合組成熟嫩,該條規(guī)定遞歸本定義中所有條款
六秦踪、
數(shù)據(jù)成員不X,為類掸茅,不為數(shù)組類型椅邓,那么集合為空。