c++构造函数介绍及一些使用的注意点
构造函数的作用:
1.创建对象
2.初始化对象中的属性
3.类型转化
类中如果没有构造函数,则c++编译器会默认给一个缺省的构造函数,但是当我们给出构造函数时,c++编译器不会给出默认的构造函数
特征
1.函数名和类名相同
2.构造函数无返回类型说明 是没有,而不是void ,即什么都不写,实际上它有返回值,返回值就是它构造的对象
3.在程序运行时,当新的对象被建立,该对象所属的类构造函数将被自动调用,在该对象生存期中也只调用这一次。不过还可以通过定位new,对其进行二次构建
4.可以类中定义,也可以在类外定义。
5.不能为虚函数
6.不可以被继承
注意点
1.加上explicit构造对象的问题
1.给构造函数加上explicit之后,就不能这样初始化对象了
当我们使用{}列表初始化这样就可以了
2. 构造函数的第二个作用,类型转换的问题
1. 当构造函数的参数列表需要一个值时的类型转换情况
此时是可以转换的
下面的例子是b对象分别通过显示类型转换和隐式类型转换进行赋值的情况
当我们给出explicit关键字之后,隐式的赋值就不可以了
第一种就相当于强制类型转换,
而下面的实际是调用其Int的构造函数,用c的值创建一个临时对象Int,接着使用"="运算符重载把这个临时对象的值赋值给b
我把operator=删除的话,它此时就报的错误是无法引用函数operator =
2.当构造函数中的形参需要两个值时的情况
此时无法进行类型转换
而当形参有默认值,即构造函数的参数列表只需要一个值时,此时又可以了
由结果可以看出,此时编译器把(a,c)当成了逗号表达式,把c的值传递给了value.
3.编译器在构造函数的时候的优化问题
using namespace std;
class student {
private:
int age_;
string name_;
public:
student(int age, string name);
void RegisterStudent(int age, string name);
void Print() {
cout << this->age_ << endl;
cout << this->name_ << endl;
}
student():age_(0),name_("小李") {}
};
student::student(int age, string name) {
age_ = age;
name_ = name;
}
int main()
{
student s = student(10, "小李");
student s2;
s2 = student(10, "小李");
return 0;
}
对于s和s2的创建方式是不一样的
对于s,本来是应该先用 (10和”小李“)构造出一个将亡值对象,然后再调用student的operator= 来给s 赋值,但此时编译器进行了优化,直接使用(10,”小李“)来构造s这个对象
当我们调试的时候就可以看出来,当构建s对象时,此时的this指针的值已经和s的地址一样了。
3.创建对象的时候尽量使用{}来创建,而不是()
using namespace std;
class student {
private:
int age_;
string name_;
public:
student(int age, string name);
void RegisterStudent(int age, string name);
void Print() {
cout << this->age_ << endl;
cout << this->name_ << endl;
}
student():age_(0),name_("小李") {}
};
student::student(int age, string name) {
age_ = age;
name_ = name;
}
此时我们通过界面就可以看出,s2这个对象和其它的颜色都不一样了。
此时编译器把它当成了一个函数声名,即返回值为student 函数名为 s2,形参列表为空的函数。
4.构造函数构造对象时,构建成员对象时与初始化列表的顺序无关,和成员对象在类中的定义顺序有关
如果按照初始化列表顺序,此时value_的值应该为1,value2_的值也应该为1,
而此时因为是按照成员变量定义的顺序,所以value_的值是一个随机值。
构造函数为什么不能定义为虚函数?
因为构造函数的一个作用就是设置虚表指针,如果把构造函数设置成虚函数,那么构造函数将在虚表中存着,那么在调用构造函数的时候,虚表指针还没有设置,这样就无法找到虚表,就无法调用构造函数,而要设置虚表指针,就必须得调用构造函数,此时就已经产生矛盾了,所以构造函数不能定义为虚函数。