再问默认构造函数

maoxing63570 2010-10-06 09:15:26
2.C++又规定,如果一个类没有提供任何的构造函数,则C++提供一个默认的构造函数(由C++编译器提供),这句话也是错误的,正确的是:
如果一个类中没有定义任何的构造函数,那么编译器只有在以下三种情况,才会提供默认的构造函数: a、如果类有虚拟成员函数或者虚拟继承父类(即有虚拟基类)时;
b、如果类的基类有构造函数(可以是用户定义的构造函数,或编译器提供的默认构造函数);
c、在类中的所有非静态的对象数据成员,它们对应的类中有构造函数(可以是用户定义的构造函数,或编译器提供的默认构造函数)。
==============================================================================================================
上面的话引自一篇博客,另外在《VC++深入详解》中见到同样的话,我对“b、如果类的基类有构造函数(可以是用户定义的构造函数,或编译器提供的默认构造函数)”话不解,(其它的由于技术不怎么样还不知道如果来测试),为了检验这段话的正确性,我做了如果下的测试


#include <iostream>
using namespace std;
class A
{
};
void main ()
{
A a;
}

这段代码对应的汇编代码如下:


00401030 push ebp
00401031 mov ebp,esp
00401033 sub esp,44h
00401036 push ebx
00401037 push esi
00401038 push edi
00401039 lea edi,[ebp-44h]
0040103C mov ecx,11h
00401041 mov eax,0CCCCCCCCh
00401046 rep stos dword ptr [edi]
21: A a;
22: }
00401048 pop edi
00401049 pop esi
0040104A pop ebx
0040104B mov esp,ebp
0040104D pop ebp
0040104E ret

在这段代码中,我们确实没看到call指令,也就是说并没有产生构造函数,那么我的问题是,如果没有构造函数,那么为什么又可以产生对象a?
Question2:先看下面的这个代码:

//代码2.cpp
#include <iostream>
using namespace std;
class A
{

};
class B:A
{
public:
B()
{
cout<<"B is constructed"<<endl;
}
};
void main ()
{
B b;
}

上面的代码对应下面的汇编代码

00401170 push ebp
00401171 mov ebp,esp
00401173 sub esp,44h
00401176 push ebx
00401177 push esi
00401178 push edi
00401179 lea edi,[ebp-44h]
0040117C mov ecx,11h
00401181 mov eax,0CCCCCCCCh
00401186 rep stos dword ptr [edi]
17: B b;
00401188 lea ecx,[ebp-4]
0040118B call @ILT+80(B::B) (00401055)
18: }
00401190 pop edi
00401191 pop esi
00401192 pop ebx
00401193 add esp,44h
00401196 cmp ebp,esp
00401198 call __chkesp (00409050)
0040119D mov esp,ebp
0040119F pop ebp
004011A0 ret

在汇编代码中我们仅可以看到0040118B call @ILT+80(B::B) (00401055)这们一句call指令,并没有看到相关的A的构造指令,但是由继承的原理我们知道要产生子类,必须先构造父类,这不就矛盾了。从以上给出的那三个条件说,“如果类的基类有构造函数”,这里我们也没给类A添加构造函数,而且代码2.cpp中,类A要产生构造函数的条件也不符合上面说的三条中的任何一条,如果按上面的三条为标准的话,那么类A也就没了默认构造函数,那么当定义子类的实例时,子类的构造函数会去找父类的构造函数先构造父类,这时无法找到,但是代码是可以通过编译的。这又是为什么?当然你也许会说你用VC6.0是可以通过编译的,但是我用VS2010也是可以通过编译的。下面说下我的测试环境
OS:win7 旗舰 32位系统
编译环境:vc6.0,vs2010(都试过)
...全文
899 80 打赏 收藏 转发到动态 举报
写回复
用AI写文章
80 条回复
切换为时间正序
请发表友善的回复…
发表回复
xionglintianxia 2011-04-11
  • 打赏
  • 举报
回复
没有构造函数,i的初始化有程序员保证,编译器不保证,系统运行时只给你一块内存而已,就这么简单![Quote=引用 79 楼 dragongou 的回复:]

构造一个全局类对象,如
class A
{
int i;
};

A a;

int main()
{
return 0;
}
有没有默认构造函数,i是怎么初始化的?
[/Quote]
dragongou 2010-11-24
  • 打赏
  • 举报
回复
构造一个全局类对象,如
class A
{
int i;
};

A a;

int main()
{
return 0;
}
有没有默认构造函数,i是怎么初始化的?
thinkboy234 2010-10-12
  • 打赏
  • 举报
回复
关注~~
cswuyg 2010-10-12
  • 打赏
  • 举报
回复
[Quote=引用 75 楼 yutaooo 的回复:]
另外,论坛中很多人都强调要看书,淡化汇编。就象左值,非要用汇编分出个原因来,我就是不能理解的。

我想他们都是经验之谈。实现毕竟有很多的自由性,拿特例去推导原则,是比较忌讳的。要么有一个广泛的实现集合去仔细分别,不过也太没效率了。[/Quote]
1、你的代码说明不了什么问题。基类有默认构造函数。派生类肯定也会有。符合产生编译器合成构造函数的条件b。
2、左值是C++才有的语法,汇编语言自然看不出来。
如果是分析C++的语法、C++的编程那就没必要过多涉及汇编,编程的时候也没必要去知道是否有构造函数,反正能定义需要的对象就行了。

但现在分析的是C++的底层实现,要是不分析汇编,那只能是按照C++标准里边告诉你的去理解,但事实上编译器又有它们各种的实现,C++程序编译出来的exe内部可能跟标准里说的不同。

3、“拿特例去推导原则”。。汗,楼主是拿特例去证明原则存在纰漏。这没什么问题。。
——————————————

另外,关于构造函数存在不存在的问题,我觉得应该讨论得差不多了,标准里的规定、编译器的实现谈到了。再讨论下去也只能是:一个人拿标准里的文字跟另一个人拿编译器的实现然后喋喋不休的纠纷。
yutaooo 2010-10-11
  • 打赏
  • 举报
回复

C的父类,B是没有显示的默认构造器的。


class A {
public:
A() {}
};

class B : public A {

};

class C : public B {

};


另外,论坛中很多人都强调要看书,淡化汇编。就象左值,非要用汇编分出个原因来,我就是不能理解的。

我想他们都是经验之谈。实现毕竟有很多的自由性,拿特例去推导原则,是比较忌讳的。要么有一个广泛的实现集合去仔细分别,不过也太没效率了。

maoxing63570 2010-10-11
  • 打赏
  • 举报
回复
[Quote=引用 66 楼 yutaooo 的回复:]
LZ是将来的大牛,咱们现在巴结一下。^_^

根据这个b)。这里说了,如果基类有,那么派生类一定有。

反过来呢?如果派生类有,基类,哦,有没有,没有说。

这里正反有两个关系。要理顺了。


经验上,在理解这类问题的时候,2个类之间的继承关系,不能完全解释清楚的。需要3个类间的继承关系。

爷爷类,父亲类,儿子类。

潜在的,我觉得LZ是在这个上面没想清楚。

另外……
[/Quote]
Thank you for your suggestions.I will take it into consideration.
gules 2010-10-11
  • 打赏
  • 举报
回复
[Quote=引用 72 楼 maoxing63570 的回复:]
引用 65 楼 gules 的回复:
怎么还在搞这个问题?拿本《Inside The C++ Object Model》不就解决了!

拜托你不要什么都《Inside c++ object mode》,要是什么问题都是这本书就可以解决的话,其它写书的人不就要回去挑粪了
[/Quote]

呵呵,要想成为技术牛人,首先得培养严谨的逻辑思维习惯!

我何时说过“什么问题都靠ITCOM这本书”?但就这个问题,此书已经解释清楚,并就你的疑问(trivial构造函数编译器合成还是不合成)也有明确的说明(各编译器的实际处理方式是不一样的)!
maoxing63570 2010-10-11
  • 打赏
  • 举报
回复
[Quote=引用 65 楼 gules 的回复:]
怎么还在搞这个问题?拿本《Inside The C++ Object Model》不就解决了!
[/Quote]
拜托你不要什么都《Inside c++ object mode》,要是什么问题都是这本书就可以解决的话,其它写书的人不就要回去挑粪了
maoxing63570 2010-10-11
  • 打赏
  • 举报
回复
[Quote=引用 67 楼 pink9527 的回复:]
看你比我专业,但是据我理解是这样的:
子类继承基类也就是父类的所有属性
如果基类有构造函数,那么系统默认子类也应该具有构造函数,并且会自动我子类创建一个构造函数
如果基类没有构造函数,那么子类也不具有构造函数,系统不会自动为子类创建一个构造函数
但是用户自己可以手动为子类创建构造函数
[/Quote]
我是计算机专业的,我只是不想把我自己的电脑变成电视机和游戏机,我只是想把我爹妈的辛苦钱做点实际的事,做点有意义的事,所以……
dengsf 2010-10-11
  • 打赏
  • 举报
回复
C++又规定,如果一个类没有提供任何的构造函数,则C++提供一个默认的构造函数(由C++编译器提供)
----------------------------------
这句话没有错,从语言的语义角度确实是这样规定的。

而生成的代码是否有该构造函数是另一回事,由编译器自行实现。
构造函数为空(即LZ所讲的无成员无基类无虚函数虚继承等等),编译器可以优化掉;
即使有,也可能inline进每个构造该类实例的代码中;
……
maoxing63570 2010-10-11
  • 打赏
  • 举报
回复
[Quote=引用 65 楼 gules 的回复:]
怎么还在搞这个问题?拿本《Inside The C++ Object Model》不就解决了!
[/Quote]
尽信书不如无书
hslinux 2010-10-11
  • 打赏
  • 举报
回复
看了半天,

“C++又规定,如果一个类没有提供任何的构造函数,则C++提供一个默认的构造函数(由C++编译器提供)”
“这句话也是错误的”,,,

这句话是否是错误的,看看C++ ISO标准文档不就了结了,置于编译器是如何实现的,跟这句话是否正确貌似没有什么必然联系。
na2650945 2010-10-11
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 gules 的回复:]

LZ:对象的内存分配与构造函数是两码事,即编译器会先分配内存再去调用构造函数(你可以对基于heap的对象手动模拟之)。
那么,对于你的困惑就在于没有搞清构造函数的本质。
一般而言,构造函数完成三个任务:
1、为对象的数据成员(内建类型)在已分配的内存上设定初值;
2、调用基类和数据成员(类类型)的构造函数在已分配的内存上设定本对象的基类和成员类部分的初值;
3、创建vptr(虚函数表指……
[/Quote]
这个不错。
na2650945 2010-10-11
  • 打赏
  • 举报
回复
Inside C++ Object Model.
xspace_time 2010-10-11
  • 打赏
  • 举报
回复
看你比我专业,但是据我理解是这样的:
子类继承基类也就是父类的所有属性
如果基类有构造函数,那么系统默认子类也应该具有构造函数,并且会自动我子类创建一个构造函数
如果基类没有构造函数,那么子类也不具有构造函数,系统不会自动为子类创建一个构造函数
但是用户自己可以手动为子类创建构造函数
yutaooo 2010-10-11
  • 打赏
  • 举报
回复

LZ是将来的大牛,咱们现在巴结一下。^_^

根据这个b)。这里说了,如果基类有,那么派生类一定有。

反过来呢?如果派生类有,基类,哦,有没有,没有说。

这里正反有两个关系。要理顺了。


经验上,在理解这类问题的时候,2个类之间的继承关系,不能完全解释清楚的。需要3个类间的继承关系。

爷爷类,父亲类,儿子类。

潜在的,我觉得LZ是在这个上面没想清楚。

另外,在分析指向虚成员函数的指针时,也要这么分析。
gules 2010-10-11
  • 打赏
  • 举报
回复
怎么还在搞这个问题?拿本《Inside The C++ Object Model》不就解决了!
maoxing63570 2010-10-11
  • 打赏
  • 举报
回复
[Quote=引用 60 楼 lkpo 的回复:]
楼主试过这段代码吗

C/C++ code
#include <iostream>
using namespace std;
class A
{
public:
A(){};
};

void main ()
{
A a;
}
[/Quote]
不试过,我只是写个代码来测试我引用的话是不是正确的,所以我做了那段话的反例
bdxxxx 2010-10-11
  • 打赏
  • 举报
回复
一句话 你两个例子中的A都什么都没做 它的构造函数是trivial的只有在需要时才被合成,但是这个构造函数是不被需要的,自然就没有了
pengzhixi 2010-10-11
  • 打赏
  • 举报
回复
嗯 标记下
加载更多回复(58)

64,691

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧