默认构造函数,为啥我的类似乎有三个?当编译器将类视为结构时?

Posted

技术标签:

【中文标题】默认构造函数,为啥我的类似乎有三个?当编译器将类视为结构时?【英文标题】:Defaults constructors, why my class seems to have three? When compilers treats classes like structures?默认构造函数,为什么我的类似乎有三个?当编译器将类视为结构时? 【发布时间】:2010-10-27 17:49:29 【问题描述】:

我一直认为,只有两个默认构造函数:没有参数的构造函数和复制构造函数。

但今天我写的是这样的:

首先我想确保在 C++ 中以 c 样式初始化结构仍然有效..

struct Foo
    int a;
    bool b;
    char* c;
    double d;
;
//..
Foo arr[2]=0, true, "a", 3.14, 1, false, "z", 42.0;

好的,这行得通。但接下来,我决定检查一下将struct 更改为class 后会发生什么。

class Bar
 public:
    int a;
    bool b;
    char* c;
    double d;
;

//..

Bar arr[2]=0, true, "a", 3.14, 1, false, "z", 42.0;//works
Bar bar;                                                 //works
Bar bar2=arr[1];                                         //works
//Bar bar3(2, false, "so", 7.0);                         //of course doesn't work
//first, second, third ways works... 

只要class Bar 没有任何私有/受保护字段(但它可以包含方法),它就可以编译。所以,只要编译器可以创建只使用结构简单特征的类,就可以编译。

第一个问题:我说的对吗?

第二个问题:它是编译器(在这种情况下为 gcc)的特性还是这正是标准所说的?

[编辑]

代码//Bar bar3(2, false, "so", 7.0); //of course doesn't work 在这里不是问题;)


PS。我仍在学习英语,但有时我会犯愚蠢的错误。我正在尽我所能,用英语写问题和答案,但是如果你能编辑我的帖子以防出现任何错误,我会非常高兴。我保证,你的努力不会白费。

【问题讨论】:

【参考方案1】:

我决定检查将结构更改为类后会发生什么。

structclass 之间的唯一区别是成员的默认可见性和默认继承模式。 struct D : B ... 等价于class D : public B public: ...

【讨论】:

【参考方案2】:

“//Bar bar3(2, false, "so", 7.0);" 看起来很正常不起作用,因为您没有使用该签名定义构造函数。为了让它工作,你需要在你的类中定义一个带有该签名的构造函数。除非您自己声明,否则编译器只会为您生成默认构造函数和默认复制构造函数。

【讨论】:

【参考方案3】:

虽然你称它为 C 风格的初始化,但它的正式名称是初始化列表。只有聚合可以使用初始化列表进行初始化(参见标准中的 8.5)。

聚合是一个数组或一个类

没有用户声明的构造函数, 没有私有或受保护的非静态数据成员, 没有基类, 并且没有虚函数。

这些是您的实际限制。这意味着您可以将初始化列表与非 POD 聚合一起使用:

struct Aggregate

   std::string s;
;

Aggregate ag =  "hello" ;

【讨论】:

【参考方案4】:

使用//Bar bar3(2, false, "so", 7.0); ,您正在调用一个不存在的 ctor。

【讨论】:

【参考方案5】:

Bar 满足 POD 类型要求,这意味着它可以像 C 结构体一样被初始化。作为一个类或结构对此没有影响。

【讨论】:

非常接近,但不完全。 Bar 是一种“聚合”类型。如果对聚合的要求比 POD 更强或更弱,我不记得了,但我认为更强。只有聚合类型可以用 ... 语法初始化。 嗯,很有趣。不知道。【参考方案6】:

我一直认为,只有 两个默认构造函数:构造函数 没有参数,并复制 构造函数。

1.是的 - 你是对的。

2.

它是编译器的(在这种情况下是 gcc) 功能

您在说什么“功能”?只需重载你的构造函数就有一个方法 Bar::Bar(int,bool,char*,double) 你一帆风顺

【讨论】:

【参考方案7】:

众所周知,C++ 中的任何类都存在默认构造函数和默认复制构造函数,无论它们是否显式声明。我认为当您使用以下语法时会发生什么:

Bar arr[2]=0, true, "a", 3.14, 1, false, "z", 42.0; 

是编译器推断出对象的类型然后调用每个对象的默认构造函数,然后分配每个字段符合其在类定义中的位置。编译器无法调用默认的拷贝构造函数,因为在创建新对象时没有直接传递相同类型的对象,也就是说,在以下情况下应该调用拷贝构造函数:

Bar a;     //default constructor is called
Bar b(a);  //default copy constructor is called
Bar c = a; //default copy constructor is called

您应该做的是将默认构造函数添加到 Bar 类,然后进行调试以了解实际发生的情况...

【讨论】:

"...无论是否明确声明。" - 这不是真的。如果给定带有例如 1 参数的构造函数,则不会生成默认构造函数。而且我不需要添加任何东西,因为我在这里不需要复制构造函数;)此外..我认为这里根本没有调用构造函数,因为这个类被视为结构。 @noisy:实际上默认构造函数只有在没有用户声明的构造函数的情况下才由编译器隐式生成。我的意思是你应该在你的类中添加一个默认构造函数和一个复制构造函数,然后进行调试,并注意你的类到底发生了什么。不同的编译器的行为也不同。我没有 gcc 编译器,所以目前无法运行测试...

以上是关于默认构造函数,为啥我的类似乎有三个?当编译器将类视为结构时?的主要内容,如果未能解决你的问题,请参考以下文章

为啥并不总是有默认构造函数[重复]

为啥当类包含任何参数化构造函数时编译器不提供默认构造函数? [复制]

试图将类作为参数传递给不同的类构造函数,但出现“转换”错误

c ++如何将类初始化器用于非默认构造的类

为啥不继承 C++ 构造函数?

为啥我们需要一个默认构造函数来在 C++ 中通过引用传递一个对象?