对于简单变量来说,可以轻松完成拷贝。
int a = 10;
int b = a;
但是对于复杂的类对象来说,不仅存在变量成员,也存在各种函数等。因此相同类型的类对象是通过拷贝构造函数来完成复制过程的。
#include<iostream>
using namespace std;
class String
{
private:
char* m_buffer;
unsigned int m_size;
public:
String(const char* string)
{
m_size = strlen(string);
m_buffer = new char[m_size + 1];
memcpy(m_buffer, string, m_size);
m_buffer[m_size] = 0;
}
~String()
{
delete[] m_buffer;
}
friend ostream& operator <<(ostream& stream, const String& string);
};
ostream& operator <<(ostream& stream,const String& string)
{
stream << string.m_buffer;
return stream;
}
int main()
{
String a = "A";
String b = a;//这里执行拷贝构造函数
cout << a << endl;
cout << b << endl;
getchar();
return 0;
}
可以看到成功拷贝了我们自己设计的String类(这里拷贝指的是默认拷贝构造函数即也是浅拷贝),当然这段代码是存在问题的
我们可以看到两块指向m_buffer内存地址相同,所以会出现多次析构的情况(即a对象析构完了,将m_buffer释放掉后,因为b对象指向的也是m_buffer区域又要释放一次已经释放掉的),这也是浅拷贝,下面会详细讲解浅拷贝和深拷贝。
拷贝构造函数的格式:
类名(const 变量类型& other)
{
.......
}
要注意变量一定是本类型的可引用变量
Test a(0,1);
Test b(a);
Test c = a;
为了解决浅拷贝导致拷贝的对象指向内存与原被拷贝对象一致,导致析构两次的问题,我们需要手动提供另一种拷贝构造函数的方式————深拷贝。
#include<iostream>
using namespace std;
class String
{
private:
char* m_buffer;
unsigned int m_size;
public:
String(const char* string)
{
m_size = strlen(string);
m_buffer = new char[m_size + 1];
memcpy(m_buffer, string, m_size + 1);
m_buffer[m_size] = 0;
}
String(const String& other)
:m_size(other.m_size)
{
m_buffer = new char[m_size + 1];
memcpy(m_buffer, other.m_buffer, m_size + 1);
}
~String()
{
delete[] m_buffer;//防止内存泄露
}
char& operator[](unsigned int index)
{
return m_buffer[index];
}
friend ostream& operator <<(ostream& stream, const String& string);
};
ostream& operator <<(ostream& stream,const String& string)
{
stream << string.m_buffer;
return stream;
}
int main()
{
String a = "A";
String b = a;//这里执行拷贝构造函数
b[0] = 'B';
cout << a << endl;
cout << b << endl;
getchar();
return 0;
}
深拷贝函数代码
String(const String& other)
:m_size(other.m_size)
{
m_buffer = new char[m_size + 1];
memcpy(m_buffer, other.m_buffer, m_size + 1);
}
可以看到两个对象的m_buffer地址不再一样。即拷贝的对象又重新分配了一份自己的m_buffer地址。
但是当我们比如有一些函数,我们本来就不需要让他拷贝(例如输出之类的函数),因为拷贝他们没有任何意义。
这里举一个例子:
这里执行后的结果:
可以看到,跟我们上面二中对象以值传递的方式传入函数参数说的一样它会调用拷贝函数,但是这是非常没有效率的,因为我们仅仅只是希望它输出,而非拷贝一份在输出,这样是没有任何意义的。
我们该如何做呢?很简单
我们只需要传引用(&)就可以
这样就可以防止无效拷贝导致效率降低的问题了。
重要:总是通过const引用去传递对象来减少无效的拷贝来增加效率
以上就是拷贝构造函数的所有内容了如果读者觉得本文章对你有收益,还请关注,点赞!