构造函数是特殊的成员函数,只要创建类类型对象,都要执行构造函数,构造函数的工作是保证每个对象的数据成员具有合适的初始值。下面将给出构造函数的特征和实用构造函数的注意事项。
1.构造函数不能申明为const,const构造函数是没有必要的。创建类类型的const对象时,运行一个普通构造函数来初始化该const对象,构造函数的工作是初始化对象,不管对象是否为const, 都用一个构造函数初始化。
2.有些成员必须在构造函数初始化列表中初始化。没有默认构造函数的类类型成员,以及const或引用类型成员,不管是哪种类型,都必须在构造函数初始化列表中初始化。可以初始化const对象或者引用类型对象,但不能对它们赋值。
3.构造函数的初始化列表中,初始化的顺序是成员在类体中被定义的顺序,而不是初始化列表中的顺序。
4.如果我们没有为类定义构造函数,编译器将会为我们定义一个默认构造函数,如果我们已经定义了构造函数,编译器将不会为我们定义默认构造函数。如果我们定义了一个默认构造函数和一个只有一个默认参数的构造函数,当我们使用不带参数的构造函数来定义一个类对象的时候,编译器会报错,代码如下:
class A
{
public:
A()
{
printf("默认构造函数\n");
}
A(int x = 0)
{
a = x;
printf("默认实参构造函数\n");
}
int a;
};
int _tmain(int argc, _TCHAR* argv[])
{
A a; //error C2668: “A::A”: 对重载函数的调用不明确
return 0;
}
5.可以用单个实参来调用构造函数定义了从形参类型到该类类型的一个隐式转换。代码如下:
class A
{
public:
A(){cout << "默认构造函数!" << endl;}
A(int i) : x(i){cout << i << " 直接初始化!" << endl;}
A(const A &a){x = a.x;cout << x << " 复制初始化!" << endl;}
~A(){cout << x << " 析构函数" << endl;}
private:
int x;
};
int main()
{
//1
printf("******1\n");
A a = 1;
}
运行结果:
在此例中,先调用的是直接初始化构造函数,然后在调用析构函数,这是为什么呢?就是因为涉及到隐式转换问题。首先将1隐式转换为A(1),然后用A(1)对a进行初始化,A a = 1;就相当于A a = A(1);还有一种情况:
class A
{
public:
A(){cout << "默认构造函数!" << endl;}
A(int i) : x(i){cout << i << " 直接初始化!" << endl;}
A(const A &a){x = a.x;cout << x << " 复制初始化!" << endl;}
~A(){cout << x << " 析构函数" << endl;}
private:
int x;
};
int main()
{
A a;
a = 1;
}
运行结果:
在此例中,首先A a;调用的是默认构造函数,执行a = 1;的时候,首先将1隐式转换为A(1),同时保存一个对象,然后再通过赋值运算将保存的对象赋给a,赋给a之后该对象便会销毁,注意,是赋给a之后便立即销毁,而不是等到主函数结束的时候才销毁。只要在主函数结束前添加system("pause");便可以得知。可以通过将构造函数申明为explicit来防止在需要隐式转换的上下文中使用构造函数。
6.当定义一个新对象并用一个同类型的对象进行初始化时,将显式使用复制构造函数,当将该类型的对象传给函数或从函数返回该类型对象时,将隐式使用复制构造函数。与默认构造函数一样,复制构造函数也可以由编译器隐式调用,复制构造函数可用于以下情况:
·根据里一个同类型的对象显式或隐式初始化一个对象。
·复制一个对象,将它作为实参传给一个函数。
·从函数返回是复制一对象。
·初始化顺序容器中的元素。
·根据元素初始化列表初始化数组元素。
有如下代码:
vector<string> vec(5);编译器先使用string默认构造函数创建一个临时对象来初始化vec,然后使用复制构造函数将临时值复制到vec的每个元素。
只包含类类型或者内置类型(但是不包含指针类型)成员的类,无需显示的定义复制构造函数,也可以复制。为了防止复制,必须显示的申明复制构造函数为private。如果复制构造函数是私有的,将不允许用户复制该类型的对象,编译器将拒绝任何进行复制的尝试。但是类的友元和成员任可以进行复制。如果想要友元和成员都不能复制,就可以申明一个private复制构造函数,但是不进行定义,因为任何使用未定义成员的尝试都会使连接失败。不定义复制构造函数和/或默认构造函数会严重局限类的使用,不允许复制对象,只能作为引用传递给函数或者从函数返回,也不能用作容器元素。