C++之拷贝构造

编程入门 行业动态 更新时间:2024-10-22 05:17:15

C++之拷贝构造

C++之拷贝构造

拷贝构造

  1. 拷贝构造
  2. 初始化列表

什么是拷贝构造?

拷贝函数,它是一种特殊的构造函数,主要用来完成一些基于同一类的其他对象的构建及初始化,用自身这种类型的对象来构造自身。

拷贝构造的定义

  1. 用户未定义拷贝构造
    系统默认提供一个隐式的拷贝构造,它会将存在于对象中的数据成员逐个的拷贝到新创建的对象中。
  2. 用户主动定义拷贝构造
    类名(const 类名& 引用名){}
    在函数体内用户可以自行决定需要执行的操作过程。

拷贝构造的示例

class CProp{char*pName;public:CProp(){}		//无参构造(默认构造)CProp(int money){}	//有参构造//拷贝构造  在这个里面把传进来的对象一一赋值给新的对象CProp(const CProp &pr)      {pName=new char[strlen(pr.pName)+1];strcpy(pName,pr.pName);}};    

拷贝构造的调用

  1. 用一个类对象去初始化该类的另一个对象时
	CProp pr1;CProp pr2(pr1);		//拷贝构造的显式调用CProp pr3 = pr1;		//拷贝构造的隐式调用CProp *pPr = new CProp(pr1);	//拷贝构造的显式调用
  1. 如果函数的形参是类的对象,以值传递的方式进行实参传递时,调用拷贝构造
void MySample(CProp p);
  1. 如果一个函数的返回值是类对象类型,以值传递的方式返回时
	CProp GetProp(){return p;}

拷贝构造引发的情况

  1. 浅拷贝

这个系统提供的构造,可以理解为用=号一个一个的赋值,那么在我们使用对象
的成员有指针申请内存的时候,那么我们就会遇到一个问题。如下:

会把A对象成员指针直接赋值给到B对象成员,这样并没有给B对象成员的指针来
重新申请内存保存内容,新的对象里面的指针和传进的指针都是指向同一块内存,
两个对象死亡时,都会调用各自的析构函数来释放内存,但是两个指针都是指向同
一个地址,那么第一个指针释放之后,第二个就没有释放的了,所以会出错。

  1. 深拷贝

给新的指针申请内存来存内容,这样就不会出现浅拷贝所出现的问题了。
如下:

  1. 什么时候应该使用深拷贝

类中有动态申请内存,必须要重写拷贝构造,来做深拷贝。
如下:
CProp是一个类,在这个类中有指针,该指针会在使用中申请内存,然后析构会
释放内存,如果没有重新定义拷贝构造,那使用:
CProp pr1;
CProp pr2=pr1;
这样就会有浅拷贝的问题

练习代码

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;class Person
{int a;char* name;
public:Person(){a = 10;name = new char[strlen("小叶") + 1];strcpy(name, "小叶");cout << "无参构造" << endl;}Person(int a, const char* name){this->a = a;this->name = new char[strlen(name) + 1];strcpy(this->name, name);cout << "拷贝成功 !" << endl;}//拷贝构造Person(const Person& p){a = p.a;name = new char[strlen(p.name) + 1];strcpy(name, p.name);cout << "带参构造" << endl;}void show(){cout << "Id :" << a <<endl<< "Name :" << name<<endl;}~Person(){if (name != NULL){delete []name;name = NULL;cout << "析构函数" << endl;}}
};//当返回值是一个对象的时候调用拷贝构造
Person fun()
{Person p(1, "Yesir");return p;
}
int main()
{/*Person p(1,"小叶");p.show();Person p2 = p;p2.show();*///匿名函数, 生命周期只有一行//Person().show();//cout << "----------" << endl;//fun();system("pause");return 0;
}

初始化列表

构造函数除了有名字,参数列表和函数体之外,还可以有初始化列表。

初始化列表的定义

class CTank{int att;int def;int hp;public:CTank():att(10),def(6),hp(200)	//初始化列表{...}};

初始化列表的特性

  1. 初始化列表也是实现类成员数据初始化的一种方式。
  2. 一些特殊的情况下,数据成员的初始化只能用初始化列表,而不能直接赋值。
  3. 初始化列表必须写在构造函数的定义体后面,用 :开头,表中用 ,分隔。
  4. 构造函数能对数据进行的操作,初始化列表也可以。反之不一定。
  5. 被初始化的成员是按照他们在类中出现的顺序来进行初始化,而不是按照他们在初始化列表中出现的顺序来进行初始化。

初始化列表的示例

//第一种
class CObject{public:	 CObject(int x, int y, int z) :objectX(x), objectY(y){}/*CObject(int x, int y){objectX = x;objectY = y;}*/int objectX, objectY;};//第二种class CNpc{public:	 CNpc(int h, int lev) :hp(h), level(lev){}/*CNpc(int h, int lev){hp = h;level = lev;//错误,常量不能被修改}*/int hp;const int level;}; 

第一种初始化列表的使用,和构造直接赋值一样效果x的值赋值给objectX,y的值赋值给objectY。
第二种初始化列表的使用,如果类里面有const常量成员必须要用初始化列表来进行赋值。

初始化列表和构造函数

  1. 初始化列表需要写在构造函数的定义后面。
  2. 初始化列表能完成构造函数不一定能完成的数据的初始化。
  3. 构造函数是函数,可以在函数体内实现对于函数的调用,初始化列表不能。

练习代码

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;class Person
{int a;char* name;
public:Person(){a = 10;name = new char[strlen("小叶") + 1];strcpy(name, "小叶");cout << "无参构造" << endl;}Person(int a, const char* name){this->a = a;this->name = new char[strlen(name) + 1];strcpy(this->name, name);cout << "拷贝成功 !" << endl;}//拷贝构造Person(const Person& p){a = p.a;name = new char[strlen(p.name) + 1];strcpy(name, p.name);cout << "带参构造" << endl;}void show(){cout << "Id :" << a <<endl<< "Name :" << name<<endl;}~Person(){if (name != NULL){delete []name;name = NULL;cout << "析构函数" << endl;}}
};//当返回值是一个对象的时候调用拷贝构造
Person fun()
{Person p(1, "Yesir");return p;
}//初始化列表
class Gad
{int a, b, c;
public:Gad(int x, int y, int z) :a(x), b(y), c(z){a = 10;b = 20;c = 30;//先运行初始化列表, 再进入函数体内}void show(){cout << a << " " << b << " " << c << endl;}
};class A
{const int a;
public://常量在定义的时候没有初始化的话, 必须得使用初始化列表对其进行初始化A():a(10){}void show(){cout << a << endl;}};class B
{int a;
public:B(int x):a(x){cout << "B的带参构造" << endl;}~B(){cout << "B的析构" << endl;}
};class C
{B b;int a;
public:C(int x):b(10),a(x){cout << "C的带参构造" << endl;}~C(){cout << "C的析构" << endl;}
};
int main()
{/*Person p(1,"小叶");p.show();Person p2 = p;p2.show();*///匿名函数, 生命周期只有一行//Person().show();//cout << "----------" << endl;//fun();B::B(12);/*Gad g(1, 2, 3);g.show();*//*A a;a.show();*///栈区: 先进后出, B->C->C->B//{C c(10); }system("pause");return 0;
}

更多推荐

C++之拷贝构造

本文发布于:2024-02-27 05:49:12,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1705412.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!