Linux提供的拷贝函数,C++之拷贝构造函数的浅copy和深copy

一、深拷贝和浅拷贝构造函数总结:

1、两个特殊的构造函数:

(1)无参构造函数:

没有参数的构造函数

Class Test

{

public:

Test()

{

//这是一个无参构造函数

}

};

当类中没有定义构造函数时,编译器默认提供一个无参构造函数,并且其函数体为空;换句话来说,就是我们在类中,不用我们程序猿自己写,编译就自动提供了无参构造函数(只是我们肉眼看不到!)

#include 

#include 

class Test{

//编译器默认给我们提供了一个无参构造函数,只是我们肉眼看不到

};

int main()

{

Test t;

return 0;

}

结果输出(编译时能够通过的):

root@txp-virtual-machine:/home/txp# g++ test.cpp

root@txp-virtual-machine:/home/txp#

(2)拷贝构造函数:

参数为const class_name&的构造函数

class Test{

public:

Test(const Test& p)

{

}

}

当类中没有定义拷贝构造函数时,编译器默认提供了一个拷贝构造函数,简单的进行成员变量的值赋值

#include 

#include 

class Test{

private:

int i;

int j;

public:

/*  Test(const Test& p)编译器默认提供这样操作的

{

i = p.i;

j = p.j;

}*/

};

int main()

{

Test t;

return 0;

}

输出结果(编译可以通过):

root@txp-virtual-machine:/home/txp# g++ test.cpp

root@txp-virtual-machine:/home/txp#

(3)注意:

在写程序的时候,定义的类对象初始化时看属于哪种类型的:

Test t;//对应无参构造函数

Test t(1);//对应有参构造函数

Test t1;

Test t2=t1;//对应拷贝构造函数

比如下面我定义的类对象属于无参构造函数(当然前提是你手写了其他构造函数,虽然说编译器会默认提供,但是既然要手写,那么三种构造函数就在定义类对象的时候按需求来写),如果只写了有参数构造函数,那么编译器就会报错:

#include 

#include 

class Test{

private:

int i;

int j;

public:

Test(int a)

{

i = 9;

j=8;

}

Test(const Test& p)

{

i = p.i;

j = p.j;

}

};

int main()

{

Test t;

return 0;

}

输出结果:

root@txp-virtual-machine:/home/txp# g++ test.cpp

test.cpp: In function ‘int main()’:

test.cpp:25:9: error: no matching function for call to ‘Test::Test()’

Test t;

^

test.cpp:25:9: note: candidates are:

test.cpp:15:3: note: Test::Test(const Test&)

Test(const Test& p)

^

test.cpp:15:3: note:   candidate expects 1 argument, 0 provided

test.cpp:10:3: note: Test::Test(int)

Test(int a)

^

test.cpp:10:3: note:   candidate expects 1 argument, 0 provided

4、拷贝构造函数的意义:

(1)浅拷贝

拷贝后对象的物理状态相同

(2)深拷贝

拷贝后对象的逻辑状态相同

(3)编译器提供的拷贝构造函数只进行浅拷贝

代码版本一:

#include 

#include 

class Test{

private:

int i;

int j;

int *p;

public:

int getI()

{

return i;

}

int getJ()

{

return j;

}

int *getP()

{

return p;

}

Test(int a)

{

i = 2;

j = 3;

p = new int;

*p = a;

}

void free()

{

delete p;

}

};

int main()

{

Test t1(3);//Test t1 3;

Test t2 = t1;

printf("t1.i = %d, t1.j = %d, t1.p = %p\n", t1.getI(), t1.getJ(), t1.getP());

printf("t2.i = %d, t2.j = %d, t2.p = %p\n", t2.getI(), t2.getJ(), t2.getP());

t1.free();

t2.free();

return 0;

}

输出结果:

root@txp-virtual-machine:/home/txp# g++ test.cpp

root@txp-virtual-machine:/home/txp# ./a.out

t1.i = 2, t1.j = 3, t1.p = 0x1528010

t2.i = 2, t2.j = 3, t2.p = 0x1528010

*** Error in `./a.out': double free or corruption (fasttop): 0x0000000001528010 ***

Aborted (core dumped)

注解:出现了段错误,仔细分析,我们发现这里释放了堆空间两次(因为我们这里没有调用拷贝构造函数,也就是自己去写拷贝构造函数;所以这种情况是浅拷贝,不能释放两次堆空间):

代码版本二(加上拷贝构造函数):

#include 

#include 

class Test{

private:

int i;

int j;

int *p;

public:

int getI()

{

return i;

}

int getJ()

{

return j;

}

int *getP()

{

return p;

}

Test(int a)

{

i = 2;

j = 3;

p = new int;

*p = a;

}

Test(const Test& t)

{

i = t.i;

j = t.j;

p = new int;

*p = *t.p;

}

void free()

{

delete p;

}

};

int main()

{

Test t1(4);

Test t2 = t1;

printf("t1.i = %d, t1.j = %d, t1.p = %p\n", t1.getI(), t1.getJ(), t1.getP());

printf("t2.i = %d, t2.j = %d, t2.p = %p\n", t2.getI(), t2.getJ(), t2.getP());

t1.free();

t2.free();

return 0;

}

输出结果:

root@txp-virtual-machine:/home/txp# g++ test.cpp

root@txp-virtual-machine:/home/txp# ./a.out

t1.i = 2, t1.j = 3, t1.p = 0xb0a010

t2.i = 2, t2.j = 3, t2.p = 0xb0a030

5、什么时候需要进行深拷贝?

(1)对象中有成员指代了系统中的资源

成员指向了动态内存空间

成员打开了外存中的文件

成员使用了系统中的网络端口

注意:一般来说,自定义拷贝构造函数(也就是我们自己手写的),必然需要实现深拷贝!

二、总结:

C++编译器会默认提供构造函数

无参构造函数用于定义对象的默认初始化状态

拷贝构造函数在创建对象时拷贝对象的状态

对象的拷贝有浅拷贝和深拷贝两种方式。

好了,今天的分享就到这里,如果文章中有错误或者不理解的地方,可以交流互动,一起进步。我是txp,下期见!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
拷贝构造函数是一种特殊的构造函数,它在创建对象时使用另一个同类的对象来初始化新创建的对象。拷贝构造函数通常用于以下情况: - 通过值传递参数给函数 - 从函数返回对象 - 在程序中创建对象的副本 拷贝拷贝拷贝构造函数的两种类型。拷贝只是复制指针,而不是复制指针所指向的内容,因此两个指针将指向同一个内存地址。这意味着,如果一个对象被修改,另一个对象也会受到影响。拷贝则是复制指针所指向的内容,而不是复制指针本身。这意味着,即使一个对象被修改,另一个对象也不会受到影响。 下面是一个C++的例子,演示了拷贝拷贝的区别: ```cpp #include <iostream> using namespace std; class Person { public: Person() { name = new char[10]; age = 0; } Person(const Person& p) { name = new char[10]; strcpy(name, p.name); age = p.age; } ~Person() { delete[] name; } void setName(char* n) { strcpy(name, n); } void setAge(int a) { age = a; } void print() { cout << "Name: " << name << ", Age: " << age << endl; } private: char* name; int age; }; int main() { Person p1; p1.setName("Tom"); p1.setAge(20); Person p2(p1); // 拷贝 p2.setName("Jerry"); p2.setAge(30); p1.print(); // 输出:Name: Jerry, Age: 20 p2.print(); // 输出:Name: Jerry, Age: 30 Person p3; p3.setName("Alice"); p3.setAge(25); Person p4 = p3; // 拷贝 p4.setName("Bob"); p4.setAge(35); p3.print(); // 输出:Name: Alice, Age: 25 p4.print(); // 输出:Name: Bob, Age: 35 return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值