一:来看一个程序优化的例子
#include <iostream>
using namespace std;
class X
{
public:
X()
{
cout << "调用了默认构造函数" << endl;
}
X(const X&)
{
cout<<"调用了拷贝构造函数"<<endl;
}
~X()
{
cout << "调用了析构函数" << endl;
}
X(int a) : m_i(a)
{
cout << "调用了X(int a)函数" << endl;
}
public:
int m_i;
};
int main(void)
{
cout << "-------begin-------" << endl;
X x0(100);
X x1 = 100;
X x2 = X(100);
X x3 = (X)100;
cout << "-------end-------" << endl;
return 0;
}
来看执行结果:
这是加了防止优化编译后的结果,,再来看看优化后的执行结果。
对比两次的执行结果可以知道,如果要用一个对象给另一个对象赋值,使用第一种代码的赋值效果是最好的,,因为它没有调用多余的构造函数,,,,后面3种赋值代码,,编译器,,首先是构造出了一个临时对象,然后临时对象通过拷贝构造函数把值赋给了自己定义的对象,,所以才多了调用拷贝构造函数这一步骤。
结论:如果要用一个对象给另一个对象赋值,使用第一种代码的赋值效果是最好的。
二:一个类是否必须有拷贝构造函数?
答:非必须,,如果一个类里只有一些普通的数据类型,例如int double等等,则不必有拷贝构造函数,因为编译器有默认的bitwise(按位拷贝)这种拷贝机制,,例如:
#include <iostream>
using namespace std;
class X
{
public:
X()
{
cout << "调用了默认构造函数" << endl;
}
~X()
{
cout << "调用了析构函数" << endl;
}
X(int a) : m_i(a)
{
cout << "调用了X(int a)函数" << endl;
}
public:
int m_i;
};
int main(void)
{
X x0;
x0.m_i=100;
X x1(x0);//如果有拷贝构造函数就会调用拷贝构造函数
cout<<x1.m_i<<endl;
return 0;
}
来看执行结果:
在没有拷贝构造函数的情况下,由于有bitwise的存在,所以x1的成员m_i它的值就会变成100了(按位拷贝)。
再来看看一下情况:
#include <iostream>
using namespace std;
class X
{
public:
X()
{
cout << "调用了默认构造函数" << endl;
}
~X()
{
cout << "调用了析构函数" << endl;
}
X(const X& p)
{
cout<<"调用了拷贝构造函数"<<endl;
}
X(int a) : m_i(a)
{
cout << "调用了X(int a)函数" << endl;
}
public:
int m_i;
};
int main(void)
{
X x0;
x0.m_i=100;
X x1(x0);//如果有拷贝构造函数就会调用拷贝构造函数
cout<<x1.m_i<<endl;
return 0;
}
程序多了一个拷贝构造函数,由于拷贝构造函数里没有任何的拷贝动作,所以输出的值是不对的,,这个时候由于有了拷贝构造函数就不会执行bitwise了。
所以要想输出的值是对的就要我们自己加上赋值的动作。
即:
m_i=p.m_i;
(3)深浅拷贝问题
来看以下例子:
#include <iostream>
using namespace std;
class X
{
public:
X()
{
p=new int(100);
cout << "调用了默认构造函数" << endl;
}
virtual ~X()
{
delete p;
cout << "调用了析构函数" << endl;
}
/* X(const X& p1)
{
p=new int(100);
cout<<"调用了拷贝构造函数"<<endl;
} */
X(int a) : m_i(a)
{
p=new int(100);
cout << "调用了X(int a)函数" << endl;
}
public:
int m_i;
int *p;
};
int main(void)
{
X x0;
x0.m_i=100;
X x1(x0);//如果有拷贝构造函数就会调用拷贝构造函数
cout<<x1.m_i<<endl;
return 0;
}
这个例子中,类里多了一个指针,由于没有拷贝构造函数,所以在执行X x1(x0)这一步时是按bitwise方式拷贝,这个时候问题就来了,由于bitwise是按值来拷贝的,也就是说,x1的p指向的那段内存单元和x0的p指向的那段内存单元是一样的,这个可以单步调试看,,,所以等到对x0和x1析构的时候,,,那就会造成对这个内存单元delete两次了,,所以这个程序会报错,,,这就是浅拷贝,,,,所以这种情况下就需要自己定义拷贝构造函数了。
改造后的代码如下:
#include <iostream>
#include<stdlib.h>
#include<cstring>
using namespace std;
class X
{
public:
X()
{
p=new int(1000);
cout << "调用了默认构造函数" << endl;
}
virtual ~X()
{
delete p;
cout << "调用了析构函数" << endl;
}
X(const X& p1)
{
m_i=p1.m_i;
p=new int(1000);
memcpy(p,p1.p,sizeof(int));//自己指向拷贝的动作,深拷贝(把目标对象的内容拷贝过来)
cout<<"调用了拷贝构造函数"<<endl;
}
X(int a) : m_i(a)
{
p=new int(1000);
cout << "调用了X(int a)函数" << endl;
}
public:
int m_i;
int *p;
};
int main(void)
{
X x0;
x0.m_i=100;
X x1(x0);//如果有拷贝构造函数就会调用拷贝构造函数
cout<<x1.m_i<<endl;
cout<<*(x1.p)<<endl;
return 0;
}
这个时候由于x0的p和x1的p不是指向同一个内存段了,,所以析构的时候就不会出现delete同一段内存两次的情况了,所以程序可以正常的执行。
程序执行结果: