深拷贝与浅拷贝
**浅拷贝:**类中的缺省拷贝构造函数,对指针形式的成员变量按字节复制,而不会复制指针所指向的内容,这种拷贝方式称为浅拷贝。
cpp
#include <iostream>
using namespace std;
class Integer{
private:
int m_i;
public:
Integer(int i = 0) {
m_i = i;
}
void printf(void) {
cout << m_i << endl;
}
};
int main(int argc, const char *argv[])
{
Integer a = 100;
Integer b = a;//实际是将b的地址指向a的地址
b.printf();
Integer c(a);//类似与b
c.printf();
return 0;
}
深拷贝:为了避免浅拷贝遇到的重复重置内存问题,获得完整意义上的对象副本,必须自己定义拷贝构造函数,针对指针的成员变量,实现对指针指向内容的复制。
cpp
#include <iostream>
using namespace std;
class Integer{
private:
int *m_i;
public:
Integer(int i = 0) {
m_i = new int(i);
}
void printf(void) {
cout << *m_i << endl;
}
~Integer(void) {
delete m_i;
}
Integer(const Integer &that) {
m_i = new int(*that.m_i);
}
};
int main(int argc, const char *argv[])
{
Integer a = 100;
Integer b = a;//实际是将b的地址指向a的地址
b.printf();
Integer c(a);//类似与b
c.printf();
return 0;
}
拷贝赋值
当两个对象进行赋值操作时,比如"i3 = i2"编译器会讲其处理为"i3.operator = (i2)的成员函数调用形式",其中"operator="称为拷贝赋值操作符函数,由该函数完成其赋值运算,其返回结果就是表达式的结果。
如果没有自定义拷贝赋值操作符函数,编译器会为该类提供缺省的拷贝赋值操作符函数,用于完成两个对象的赋值操作。
但是编译器提供的缺省拷贝赋值函数,和缺省拷贝构造函数类似,也是浅拷贝,有"double free"和"内存泄露"的问题,这时需要自定义深拷贝赋值函数。
拷贝赋值符函数格式为:
cpp
Integer &operation = (const Integer &that){
}
/*
Integer:类名称
&operation= :固定写法
that:指针
*/
cpp
#include <iostream>
using namespace std;
class A{
private:
int *m_pi;
public:
A(int i = 0) {
m_pi = new int(i);
}
void printf(void) {
cout << *m_pi << endl;
}
~A(void) {
cout << "~A" <<endl;
delete m_pi;
}
A(const A &that) {
m_pi = new int(*that.m_pi);
}
};
int main(int argc, const char *argv[])
{
A a = 100;
a.printf();
A b = a;
b.printf();
b = a;
return 0;
}
/*运行结果报错
linux@linux:~/cplusplus$ ./a.out
100
100
~A
~A
*** Error in `./a.out': double free or corruption (fasttop): 0x09a57008 ***
Aborted (core dumped)
*/
String类的编程实现
实现一个字符串String,为其提供可接受c风格字符串的构造函数、析构函数、拷贝构造函数和拷贝赋值函数。
cpp
#include <iostream>
#include <cstring>
using namespace std;
class String{
private:
char *str;
public:
String(const char *str) {//类型转换构造函数
this->str = new char(strlen(str) +1);
strcpy(this->str,str);
}
String(const String &that) {//拷贝构造函数
str = new char[strlen(that.str) +1];
strcpy(str, that.str);
}
String &operator=(const String &that) {//拷贝赋值
if (this != &that) {
delete []str;//删除原本的地址
str = new char[strlen(that.str) +1];//申请新地址
strcpy(str, that.str);//拷贝内容到新地址中
}
return *this;
}
~String(void) {
delete str;
}
void print(void) {
cout << str << endl;
}
char *c_str(void) {
return str;
}
};
int main(int argc, const char *argv[])
{
String s1 = "hello";//类型转换构造函数
s1.print();
String s2 = s1;//拷贝构造函数
s2.print();
String s3 = "world";//类型转换构造函数
s2 = s3;//拷贝赋值
s2.print();
cout << s3.c_str() << endl;
return 0;
}