这几天一直有一个问题在我大脑里挥之不去,之前面试实习的时候也被问过,但是回答的不好:
面试官问:你知道的构造函数有哪些?
我说:无参构造函数、有参构造函数、拷贝构造函数、移动构造函数,*()&&*(关于一些函数的说明);
面试官说:其实拷贝构造函数、移动构造函数这些都可以叫有参构造函数%……&&*;
所以,现在在看到这个问题,我沉思了。究其原因,还是网上搜罗的答案太良莠不齐了,感觉很多都是自己诹的名词,随手摆上去的,有点坑了我们这些小辈了,当然,也或者我当时并没有仔细查阅资料,没有搜到正确的解释,就胡乱背了。
废话不多说,就目前来看,个人感觉我应该是整明白这些构造函数了,现在来说一说,如果大家觉得哪些地方说的不对,恳请赐教!!
01. 什么是构造函数,有什么用?
构造函数是类中的一个特殊的类成员函数,主要用来在创建对象时初始化对象,即为对象成员变量赋初值;
【来自百度百科构造函数_百度百科 (baidu.com)】
02. 常用构造函数有哪几种,写法是什么?
常用构造函数:默认构造函数、普通构造函数、拷贝构造函数、移动构造函数
2.1 默认构造函数:
class A{
A(){
cout<<"我是默认构造函数\n";
}
}
2.2 普通构造函数:
class A{
A(int a ,int b ){
cout<<"我是普通构造函数\n";
}
}
2.3 拷贝构造函数:
class A{
A(const A& tmp){
cout<<"我是拷贝构造函数\n";
}
}
2.4 移动构造函数:
class A{
A(A &&c){
cout<<"我是移动构造函数\n";
}
}
03.什么时候调用拷贝构造函数?
调用拷贝构造函数的三种场合:
1. 用一个类对象初始化另一个类对象时;
2. 当一个函数以值传递的方式传递类对象时;
3. 当一个函数返回一个局部类对象时;
class A{
A(){
cout<<"我是默认构造函数\n";
};
A(int a ,int b ){
cout<<"我是普通构造函数\n";
};
A(const A& tmp){
cout<<"我是拷贝构造函数\n";
};
/*
A(A &&c){
cout<<"我是移动构造函数\n";
};
*/
};
void fun1(A b){
cout<<"我是fun1\n";
}
A fun2(){
A c;
cout<<"我是fun2\n";
return c;
}
int main(){
A a;//调用默认构造函数;
A b(1,2);//调用普通构造函数;
//调用拷贝函数的三种方式:
//用一个类对象初始化另一个类对象
A c(b);
A d=b;
//一个函数的参数是类对象时
fun1(b);
// 一个函数的返回值是局部类对象时
A e=fun2();
}
04 调用拷贝构造函数的注意事项
在上述三种方法中,第三种方法可能会出现以下情况:
1. 编译器处于ROV(return Optimization Value)状态下,不会打印拷贝信息;
2. 当类构造方法中出现移动构造函数时,不会打印拷贝信息;
针对第一种问题,是因为编译器优化的结果,通过以下方式解决:
- 如果你是用命令行工作的,解决的办法,是在编译命令中加上“-fno-elide-constructors”参数,例g++ -fno-elide-constructors testReturn.cpp
- 在CodeBlocks中,通过菜单依次选:settings->Compiler,在Global compiler settings部分,选择Other compiler options 和 Other resource compiler options,在文本框中写入“-fno-elide-constructors”【参考(1条消息) C++返回值为对象时拷贝构造函数不执行怎么办?_青春是首不老歌丶的博客-CSDN博客_拷贝构造函数不执行】
- VS中直接右击文件名,点击属性,点击Optimization,看到编译器优化,下拉菜单点击禁止优化
针对第二种问题,则是因为,当移动构造与拷贝构造一同出现时,编译器会优先执行移动构造函数,因此,不会出现拷贝构造的相关信息。这是与返回值和参数有关的。
已知 左值引用 &,右值引用 &&;
对于拷贝构造函数,参数 —— const 类 & 类名,为左值引用类型;
对于移动构造函数,参数—— 类&&类名, 为右值引用类型;
而第三种方式返回的类对象为临时变量,是没有名字与地址的,属于右值类型;
所以 表面上 A e 接收的是一个类对象,是用一个类对象初始化另一个类对象,但实际上,此时调用的是移动构造函数。
题外话:关于赋值运算符“=”
对于很多博客上提到 “赋值构造函数”,这个属实让我迷茫了一段时间,心里纳闷为什么这些都没听过,这个赋值构造函数 与 赋值运算符是什么关系?
但实际上,写法上都是这样:
A& operator=(const A&f){
cout<<"我是赋值函数\n"<<endl;
}
我不知道“赋值构造函数”这个函数是不是书上有明确提过,不做评论,个人感觉提到过的各种类型的构造函数,算是对默认构造函数的重载,这个“赋值构造函数”写法上到不是重载,甚至有人说这个是浅拷贝,我就满脸黑人问号了。。。。
总之,以上就是我个人对构造函数的总结,如果有帮助最好,如果有不对的地方,希望大家也能够给予指正!