Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/157.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 什么是骨料和豆荚,它们如何/为什么特别?_C++_C++11_Aggregate_C++17_Standard Layout_C++20 - Fatal编程技术网

C++ 什么是骨料和豆荚,它们如何/为什么特别?

C++ 什么是骨料和豆荚,它们如何/为什么特别?,c++,c++11,aggregate,c++17,standard-layout,c++20,C++,C++11,Aggregate,C++17,Standard Layout,C++20,这是关于骨料和豆荚的,包括以下材料: 什么是聚合 什么是POD(普通旧数据) 它们有什么关系 它们是如何和为什么特别的 C++11有什么变化 如何阅读: 这篇文章相当长。如果您想了解聚合和POD(普通的旧数据),请花时间阅读。如果您只对聚合感兴趣,请只阅读第一部分。如果你只对PODs感兴趣,那么你必须首先阅读聚合的定义、含义和示例,然后你可以跳转到PODs,但我仍然建议你完整阅读第一部分。集合的概念对于定义豆荚至关重要。如果您发现任何错误(即使是很小的,包括语法、文体、格式、语法等),请留下评

这是关于骨料和豆荚的,包括以下材料:

  • 什么是聚合
  • 什么是POD(普通旧数据)
  • 它们有什么关系
  • 它们是如何和为什么特别的
  • C++11有什么变化
如何阅读: 这篇文章相当长。如果您想了解聚合和POD(普通的旧数据),请花时间阅读。如果您只对聚合感兴趣,请只阅读第一部分。如果你只对PODs感兴趣,那么你必须首先阅读聚合的定义、含义和示例,然后你可以跳转到PODs,但我仍然建议你完整阅读第一部分。集合的概念对于定义豆荚至关重要。如果您发现任何错误(即使是很小的,包括语法、文体、格式、语法等),请留下评论,我会编辑

这个答案适用于C++03。对于其他C++标准,请参阅:

什么是集合,为什么它们是特殊的 < C++ >标准(C++ 03 8.5.1节1)<强> >:

聚合是没有声明用户的数组或类(第9条) 构造函数(12.1),无私有或受保护的非静态数据成员(第11条), 没有基类(第10条),也没有虚函数(第10.3条)

好吧,让我们分析一下这个定义。首先,任何数组都是一个聚合。类也可以是聚合,如果…等等!没有关于结构或联合的说明,它们不能是聚合吗?是的,他们可以。在C++中,术语“代码>类< /COD>”指的是所有类、结构和联合。因此,类(或结构或联合)是聚合的当且仅当它满足上述定义中的条件时。这些标准意味着什么

  • 这并不意味着聚合类不能有构造函数,事实上它可以有默认构造函数和/或副本构造函数,只要它们是由编译器隐式声明的,而不是由用户显式声明的

  • 没有私有或受保护的非静态数据成员。您可以拥有任意多个私有和受保护的成员函数(但不是构造函数)以及任意多个私有或受保护的静态数据成员和成员函数,并且不违反聚合类的规则

  • 聚合类可以具有用户声明/用户定义的复制赋值运算符和/或析构函数

  • 数组是聚合的,即使它是非聚合类类型的数组

现在让我们看一些例子:

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
};
你明白了。现在让我们看看聚合是如何特殊的。与非聚合类不同,它们可以用大括号
{}
初始化。这种初始化语法通常用于数组,我们刚刚了解到这些是聚合。那么,让我们从它们开始

类型数组_name[n]={a1,a2,…,am}

如果(m==n)
数组的第i个元素用ai初始化
如果(m
数组的前m个元素用a1、a2、…、am初始化,其他
n-m
元素(如有可能)用值初始化(术语解释见下文)
如果(m>n)则为else
编译器将发出一个错误
else(这是一种完全不指定n的情况,如
inta[]={1,2,3};

假设数组(n)的大小等于m,因此
inta[]={1,2,3}
相当于
inta[3]={1,2,3}

当标量类型的对象(
bool
int
char
double
、指针等)被值初始化时,表示该类型的对象被初始化为
0
bool
false
double
0.0
等)。当初始化具有用户声明的默认构造函数的类类型的对象时,将调用其默认构造函数。如果默认构造函数是隐式定义的,那么所有非静态成员都是递归初始化的。这个定义是不精确的,有点不正确,但它应该给你一个基本的想法。无法初始化引用的值。例如,如果非聚合类没有适当的默认构造函数,则该类的值初始化可能会失败

阵列初始化示例:

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}};
在上述示例中,
y.c
a'
初始化,
y.x.i1
10
y.x.i2
20
y.i[0]
20
初始化,
y.i[1]
30
y.f
初始化值,即用
0.0
初始化。受保护的静态成员
d
根本没有初始化,因为它是
static

聚合联合的不同之处在于,可以仅使用大括号初始化其第一个成员。我认为,如果你在C++中足够先进,甚至可以考虑使用联合(它们的使用可能非常危险,必须仔细考虑),那么你可以在标准中查找工会的规则:p> 现在我们知道了聚合的特殊之处,让我们试着理解类的限制;这就是为什么他们会在那里。我们是
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
};
#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
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;
}
struct Aggregate {
    Aggregate() = default; // asks the compiler to generate the default implementation
};
struct NotAggregate {
    int x = 5; // valid in C++11
    std::vector<int> s{1,2,3}; // also valid
};
// 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
};
// 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
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;
struct Base {};
struct Derived : Base { Base b; };

Derived d;
static_cast<Base*>(&d) == &d.b;
struct A
{
  int a = 3;
  int b = 3;
};
struct B1 // not a aggregate
{
    int i1;
    B1(int a) : i1(a) { }
};
struct B2
{
    int i2;
    B2() = default;
};
struct M // not an aggregate
{
    int m;
    M(int a) : m(a) { }
};
struct C : B1, B2
{
    int j;
    M m;
    C() = default;
};
C c { { 1 }, { 2 }, 3, { 4 } };
cout
    << "is C aggregate?: " << (std::is_aggregate<C>::value ? 'Y' : 'N')
    << " i1: " << c.i1 << " i2: " << c.i2
    << " j: " << c.j << " m.m: " << c.m.m << endl;

//stdout: is C aggregate?: Y, i1=1 i2=2 j=3 m.m=4
struct D // not an aggregate
{
    int i = 0;
    D() = default;
    explicit D(D const&) = default;
};
struct B1
{
    int i1;
    B1() : i1(0) { }
};
struct C : B1 // not an aggregate
{
    using B1::B1;
};
struct B { int i; }; // standard-layout class
struct C : B { }; // standard-layout class
struct D : C { }; // standard-layout class
struct E : D { char : 4; }; // not a standard-layout class
struct Q {};
struct S : Q { };
struct T : Q { };
struct U : S, T { }; // not a standard-layout class
struct X {
    X() = delete;
};
class A { protected: A() { }; };
struct B : A { B() = default; };
auto x = B{};
struct X { int a, b; };
std::vector<X> xs;
xs.emplace_back(1, 2); // error
template <typename T>
struct Point {
    T x, y;
};

Point p{1, 2}; // error
template <typename T> Point(T, T) -> Point<T>;