C++---this指针和四个默认函数

(一)this指针

下面是一个简单的商品类

#include<iostream>
using namespace std;
#pragma  warning (disable:4996)
class CGoods
{
public:
	CGoods(char *name, float price, int amount)
	{
		cout << "CGoods::CGoods(char*,float,int)" << endl;
		mname = new char[strlen(name) + 1]();
		strcpy(mname, name);
		mprice = price;
		mamount = amount;
	}
	~CGoods()
	{
		cout << "~CGoods()" << endl;
		delete[]mname;
		mname = NULL;//防止野指针生成
	}
	void Show()
	{
		cout << "name:" <<mname << endl;
	}
private:
	char *mname;
	float mprice;
	int mamount;
};
int main()
{
	CGoods good1("good1", 1000, 20);
	//good1 = "good2";
	
	CGoods good2("good2", 2000, 10);
	good1.Show();
	good2.Show();
	return 0;
}

结果:

有一个疑问的,Show()函数原型并没有指出是哪一个对象的名称,为什么调用的时候会打印相应对象的名称。下面是C语言中打印名称。Show函数中的形参会接收good1和good2的地址,从而知道要打印的是哪个商品的名称。而C++中Show函数你并没有任何形参来接收对象的地址。原因是普通成员方法中都有this指针,指向对象的内存。

该例子中this指针类型为CGoods *const this

注意:   this指针的指向不能被改变

(二)默认函数

  • 构造函数:初始化对象的内存空间
  1. 对象生成:对象开辟内存,调用构造函数
  2. 系统提供的默认的构造函数    CGoods( ) { }  用户提供系统就不会在提供
  3. 不能手动调用(构造函数是类成员方法用于生成对象的,对象不完整不能调用构造函数,不能决定自己的出生)
  4. 可以重载(生而不同)
  5. 存在this指针,指向的是对象的内存
  • 析构函数:释放对象所占资源

栈上   系统开辟和释放

堆上   用户开辟和释放

  1. 对象销毁:调用析构函数,释放对象所占内存
  2. 系统提供的默认的析构函数    ~CGoods( ) { }  用户提供系统就不会在提供
  3. 可以手动调用但不建议(退化成一个普通的成员方法,系统还会在调用一次析构函数。析构函数中指针不置成NULL,会释放两次程序崩溃。可以决定自己的死亡)
  4. 不可以重载(死了都一样)
  5. 存在this指针,指向的是对象的内存

构造与析构的顺序:先构造后析构。由于内存是在栈上开辟,就要遵循栈的规则,所以,多个对象时,先构造的后析构。

  • 拷贝构造函数
  1. 作用:用一个已存在的对象生成一个相同类型的新对象。
  2. 形参必须用引用,防止形参对象构造递归构造
  3. 有指针类型,考虑是否实现深拷贝

(1)默认的拷贝构造函数是浅拷贝,程序崩溃。

CGoods(const CGoods& rhs)
	{
		mname = rhs.mname;
		mprice = rhs.mprice;
		mamount = rhs.mamount;
	}
CGoods good1("good1", 1000, 20);
CGoods good2 =good1;//用一个已存在的对象生成一个相同类型的新对象。

(2)成员变量中有指针就应该实现深拷贝。

//深拷贝版本的拷贝构造函数
CGoods (const CGoods& rhs)
{
    mname = new char[strlen(rhs.mname)+ 1]();
    strcpy(mname,rhs.mname);
    mprice  = rhs.mprice;
    mamount = rhs.mamount;
}

(3)没有&,调用函数是一个死循环,形参对象无法生成。有&,就不需要调用函数生成形参。

  • 赋值运算符重载函数
  1. 作用:用一个已存在对象,赋值给相同类型的对象。
  2. 形参const,防止修改实参,接收隐式生成临时对象。
  3. 设计流程:防止自符值,释放就资源,开辟新资源,赋值。

(1)系统默认给出的赋值运算符重载是浅拷贝,程序崩溃。

//自赋值判断
	CGoods & operator =(const CGoods&rhs)
	{
		if (this == &rhs)
		{
			return *this;
		}
		mname = rhs.mname;
		mprice = rhs.mprice;
		mamount = rhs.mamount;
	}

(2)深拷贝

//自赋值判断
	CGoods & operator =(const CGoods&rhs)
	{
		cout << this << " operator =" << endl;
		if (this != &rhs)
		{
			delete []mname;//释放旧内存
			mname = new char[strlen(rhs.mname) + 1];开辟空间
			strcmp(mname,rhs.mname);//赋值
		    mprice = rhs.mprice;
		    mamount = rhs.mamount;
		}
		return *this;	
	}

CGoods & operator =(const CGoods&rhs)

(3)引用:使用&效率会高,&支持连续赋值

 (4)const:CGoods & operator =(const CGoods&rhs):防止实参被修改,接收隐式生成的临时量(常量),所以要用常引用。

临时量:临时对象和临时变量。内置产生的临时量:常量(存储器);自定义类型产生的临时量:变量(内存)

显示生成临时对象:程序指明要生成的临时对象类型,good3 = CGood("good3")

隐式生成临时对象:编译器推演需要的对象类型,good3 = "good3"变得和引用帝乡一样的生存周期。

生存周期:表达式结束,;?

引用会提升临时对象的生存周期,使临时对象

CGood = char*无法转换,“good3”调用带一个参数的构造函数,生成临时对象,在赋值给rhs对象,当表达式结束临时对象销毁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值