深度分析构造函数,带你了解隐式转换,深拷贝浅拷贝,以及c++11的移动构造函数,不需要长篇大论的文章,几个测试实例轻松解决
#include <iostream>
using namespace std;
class student
{
int age;
int num;
public:
//默认构造
student();
//有参构造
student(int age,int num);
//拷贝构造
student(student& stu);
//转换构造
student(int age);
//移动构造
student(student&& stu);
void getstu();
void setstu();
~student();
};
student::student()
{
this->age = 18;
this->num = 0;
}
student::student(student& stu)
{
cout << "transform" << endl;
this->age = stu.age;
this->num = stu.num;
}
student::student(int age, int num)
{
this->age = age;
this->num = num;
}
student::student(int age)
{
cout << "transform" << endl;
this->age = age;
this->num = 666;
}
student::student(student&& stu)
{
cout << "move" << endl;
this->age = stu.age;
this->num = stu.num;
}
void student::getstu()
{
cout << this->age << " " << this->num << endl;
}
void student::setstu()
{
this->age = 0;
this->num = 0;
}
student::~student()
{
cout << "destroy" << endl;
}
示例一
int main()
{
student stu1=666;//隐式调用单个参数的构造函数(转换构造)
student stu2=stu1;//隐式调用拷贝构造,这里是深拷贝
stu1.getstu();
stu2.getstu();
stu2.setstu();//修改stu的成员变量
stu1.getstu();
stu2.getstu();
}
结果
这里打印2个transform说明分别走了转换构造和拷贝构造,且为深拷贝,因为我修改了stu2的值后,stu1的值并没有发生改变。
这里我借此一句话总结浅拷贝和深拷贝的区别,浅拷贝只是复制了另一个对象的指针,最后两个对象同时指向一个内存空间,一个对象修改,另一个也会受到影响。深拷贝就是连内存空间都复制了,两个对象不会互相影响。
示例二
int main()
{
student* stu1 = new student();//默认构造
student* stu2 = stu1;//浅拷贝
stu1->getstu();
stu2->getstu();
stu2->setstu();
stu1->getstu();
stu2->getstu();
return 0;
}
这里用构造对象指针,居然不走拷贝构造了,而且是浅拷贝,stu1,stu2,公用一个内存空间,所一说编译器很奇怪,一会这样一会那样,因此为避免这种情况,我们需要在单参数构造函数前加上explicit关键字以防止隐式转换。
class student
{
int age;
int num;
public:
//默认构造
student();
//有参构造
student(int age,int num);
//拷贝构造
explicit student(student& stu);
//转换构造
explicit student(int age);
void getstu();
void setstu();
};
这样我就不可能用=去实例化对象,避免了一些异常情况的发生。
而且在测试时我使用qt的编译器测试时
student stu1=10;
这种情况是不被允许的,因为这涉及到了右值引用的问题
c++面试摘录(三) | 右值引用_无规则编程程序员的博客-CSDN博客
所以说就是规规矩矩写正常的构造函数,加上关键字以防止隐式转换,就不会出那么多问题。
c++98/03的构造函数讲完了,还剩最后一个c++11的新构造函数移动构造函数
其实和移动构造和拷贝构造很像,但还是有差别,拷贝构造,会额外复制一个临时对象,会占用内存,在拷贝结束后析构,这样既费时又会消耗内存,因此移动构造应运而生。
移动构造的参数是一个右值对象,右值是什么可以看上面的链接。并可以借助于move函数;move函数的作用是把一个左值转成右值。move函数下的移动构造,可以直接将要拷贝对象的内存拿来用,而不用构造一个临时对象。移动构造性能上优于拷贝构造。
示例三
int main()
{
student stu1(100, 100);
student stu2(move(stu1));
stu2.getstu();
stu1.getstu();
return 0;
}
这里要注意的是按照move的作用会把stu1的内存给stu2,然后stu1会销毁,但事实上它到函数结束才调用析构,是因为只有在stu2离开了自己的作用域的时候才会析构,所以,如果继续使用stu2
的变量,可能会发生意想不到的错误。