默认构造函数

来源:互联网 发布:linux文件压缩命令 编辑:程序博客网 时间:2024/05/21 19:45







代码一:

复制内容到剪贴板程序代码
#include <iostream>
using namespace std;

class AA
{
};

int main()
{
    AA *a=new AA();    
    return 0;
}

执行正确,说明编译器为我们创建了默认了构造函数(没有参数的构造函数)。

代码二:
复制内容到剪贴板程序代码
#include <iostream>
using namespace std;

class AA
{
public:
    AA(){cout<<"自定义默认构造函数"<<endl;}
};

int main()
{
    AA *a=new AA();    
    return 0;
}

执行正确并输出了文本,说明使用了我们自定义的默认构造函数。

代码三:
复制内容到剪贴板程序代码
#include <iostream>
using namespace std;

class AA
{
public:
    AA(int a, int b){}
};

int main()
{
    AA *a=new AA();    
    return 0;
}

执行出错,提示缺少默认的构造函数。

代码四:
复制内容到剪贴板程序代码
#include <iostream>
using namespace std;

class AA
{
public:
    AA(){cout<<"自定义默认构造函数"<<endl;}
    AA(int a, int b){}
};

int main()
{
    AA *a=new AA();    
    return 0;
}

执行正确并输出文本,说明使用了我们自定义的默认构造函数。

总结

在C++中,当我们没有为类定义任何构造函数时,编译会创建默认构造函数;如果我们为类定义了一个构造函数,无论该构造函数是默认构造函数,还是非默认构造函数,编译器都不再为我们创建默认构造函数,在C#中也是这样子的。 




很多C++书上都说:当你设计一个类的时候,没显示申明任何构造函数时,编译器将帮你生成一个默认构造函数(公有的、内联的、无参的)。包括我自己也一直深信不疑,直到今天翻阅了“深度探索C++对象模型”时,才发觉不完全是这样的。那么既然是错误的,为什么没人发觉并纠正那种的说法?

我想了下可能是因为:

1)认同那种说法的人和我一样,不求甚解。

2)其他书籍说“有生成但什么事都不做” 和 “《深度探索C++对象模型》中阐述是根本不生成" , 其实从最终的表现效果来看是没区别的, 即啥事都没发生。所以人们就觉得无伤大雅没关系,就纵容“有生成但什么事都不做”说法泛滥。

下面我讲下真实情况:

1)当你设计一个类时,若显示申明了任何构造函数,编译器绝对不会再帮你生成,但是在需要的时候编译器会在所有用户申明的构造函数中安插一些编译器需要的代码,改造现有的所有构造函数让它们都满足编译器的需要,比如在它们中安插初始化vptr指针值的操作代码。

2)当你设计一个类时,若没显示申明任何构造函数,编译器将会在需要时,才会生成默认构造函数(公有的、内联的、无参的)要注意编译器生成的只会满足编译器的需要,不会满足程序的需要。

那么什么时候才是编译器需要,有下面4种情况:

a)类中含有一个或一个以上的非静态成员对象有默认构造函数(不管用户申明的还是编译器生成的)。

b) 类自身不含任何构造函数,但是其基类含有默认构造函数(不管用户申明的还是编译器生成的)。

c) 类中含有虚函数 (不管该类自己的还是继承而来的)。

d) 类继承链路上有虚基类。

在这4种情况下编译器才会为那些用户无申明任何构造函数的类生成默认构造函数生成的默认构造函数,只满足编译器的需要即 :

对于a情况为了调用成员对象的默认构造函数

对于b情况为了调用基类的默认构造函数

对于c情况为了初始化vptr

对于d情况为了初始化虚基类指针

而其他的非静态成员数据初始化是程序员自己的任务。

3)除上述两种情况外,编译器根本不生成默认构造函数。针对这种情况你可能会疑惑:全局对象、栈对象、堆对象是怎么初始化的?全局对象在进入main函数之前被初始化0,栈对象、堆对象根本不初始化。

综上所述:做好的做法是用户自己显示申明,这样可以明确该类的真正要表现的行为。 




原创粉丝点击