构造函数是特殊的成员函数,只要创建类类型的新对象,都要执行构造函数,无返回值,函数名与类名相同,可在类内或者外部定义,受访问权限控制。
一、默认构造函数与构造函数重载
如果没有自己声明一个构造函数,编译器会为该类生成一个默认的构造函数。如果自己定义了构造函数,编译器将不会为你生成默认构造函数,但是你可以编写自己的默认构造函数(1.无参数的构造函数2.所有形参都有默认值的构造函数 这两种的自己定义的默认构造函数只能有一种)
构造函数的数量没有限制,可以重载。
关于默认构造函数的参考文章 http://blog.youkuaiyun.com/hankai1024/article/details/7947989
二、构造函数的执行
构造函数从概念上来说,分为两个过程,初始化过程和计算过程。初始化过程在计算过程开始之前
2.1构造函数初始化过程是指对构造函数中的成员变量进行初始化的过程。
1.构造函数可以通过初始化式来显示的对成员变量进行初始化。对于类类型的成员变量可以调用其定义的任意类型的构造函数
2.对于类的成员变量,如果没有在初始化式中进行显示的初始化,则使用与初始化变量相同的规则来进行初始化。规则如下
(1)对于类类型的数据成员,运行该类型的默认构造函数;
(2)对于内置或复合类型的成员,在局部作用域中这些成员没有初始化值,而在全局作用域中初始化为0;
3.如果对于一个类类型的成员变量,没有提供初始化式,同时该类型没有默认的构造函数,编译器尝试使用默认构造函数将会失败。
4.对于一些类型的成员变量,必须使用初始化式进行初始化。包括:没有默认构造函数的的类类型成员、const成员、引用类型成员。
5.成员初始化顺序不依靠在初始化列表里的顺序,依赖于在类中定义的顺序。
2.2计算过程由构造函数体中的所有语句组成。
在构造函数函数体内的对于成员变量的赋值操作,对于类类型的成员,需要考虑相应的操作函数。
建议:使用构造函数初始化列表。原因主要是1.对于某些数据成员必须使用初始化式列表来进行初始化。2.对于一些类类型的成员变量,无论是否显示的在初始化列表中进行初始化,已经在初始化过程中进行了初始化(使用默认构造函数),因此在构造函数函数体内再进行赋值,在效率上有一定的影响。
eg:构造函数执行的简单例子
class A
{
public:
A(int a){cout<<"A constructor1"<<endl;};
A(){cout<<"A constructor"<<endl;};
};
class B
{
public:
B(int b){cout<<"B constructor1"<<endl;};
B(){cout<<"B constructor"<<endl;};
};
class C
{
public:
A a;
B b;
C(int c);
C(double c){cout<<"C constructor2"<<endl;}
C(){cout<<"C constructor"<<endl;};
};
C::C(int c):b(c),a(c){cout<<"C constructor1"<<endl;}
int main()
{
C c;//调用C(),初始化过程调用A,B的默认构造函数
C c1(1);//调用C(int),初始化过程按照初始化列表显示调用A,B构造函数
C c2(1.2);//调用C(double),初始化过程调用A,B的默认构造函数
return 0;
}
输出结果为
三、构造函数的隐式类型转换的问题。
{
public:
int d;
D(){cout<<"D constructor"<<endl;}
D(int d){this->d=d;cout<<"D constructor1"<<endl;};
D & operator=(const D &d){cout<<"复制赋值运算符"<<endl;return *this;}
};
int main()
{
D d1;
d1=1;
return 0;
}
输出结果
结果分析:类D 中包含形参为int的构造函数,即定义了一个隐式的类型转换,将一个int类型的量赋值给D类对象时,会发生转换,即生成一个以1作为实参的D类型的对象,然后将该对象赋值给d1,因此会调用一次构造函数,一次复制赋值运算符。
可以通过explicit来声明构造函数,从而防止在需要隐式转换的上下文中使用构造函数。即explicit D(int d){...};

被折叠的 条评论
为什么被折叠?



