C++面向对象总结(三)各种对象的生命周期

class CGoods
{
public:
	CGoods(char *const name, int count, float price)
	{
		if (name == NULL)
		{
		_name = new char;
		 *_name = '\0';   //如果是空也给分配一个字节内存,避免操作空指针挂掉
		}
		else
		{
			_name = new char[strlen(name) + 1];
			strcpy(_name, name);
		}
		_count = count;
		_price = price;
	}
	//拷贝构造函数,生成新对象,
	//该方法属于this和src两个对象共有的,所以可以直接访问对象的成员变量和方法
	CGoods(CGoods const &src)//src指向的是右值,this指向的是左值
	{
		//开辟一个和src一样大的内存,不能和src指向同一块内存
		_name = new char[strlen(src._name) + 1]; 
		//将this指针的内存中数据初始化为src对象的内存中的数据
		strcpy(_name,src._name);
		_count = src._count;
		_price = src._price;
	}
	void show();
	void setname(char *name){ strcpy(_name, name); }
	void getname(char *name){ strcpy(name, _name); }
	//char *getname(){ return _name ;}   
	//该函数会将_name的地址返回回去,如果类外拿到地址,可以通过地址解引用来修改内存中的值,不满足面向对象的封装
	float getprice(){  return _price; }

//赋值运算符的重载函数
	void operator=(const CGoods &src)
	{
		//1.防止自赋值,this保存的地址和src引用的对象的地址一样时
		if (this == &src)
			return;
		//2.在接收其他对象的数据之前,先要删掉自己原来已有的外部资源
		delete _name;
		//防止浅拷贝,重新申请新的空间,并用src的数据给赋过去
		_name = new char[strlen(src._name) + 1];
		strcpy(_name, src._name);
		_count = src._count;
		_price = src._price;
	}

private:
	char *_name;
	int _count;
	float _price;
};
//类外定义,函数名前加上类的作用域,告诉编译器产生的这个函数符号是类的作用域下的
void CGoods::show() 
{ 
	cout << "name: " << _name << "price: " << _price << "count:" << _count << endl; 
}

第一部分:认识编译器对对象生成过程的优化

对象的基本分类:
1.栈上的
2.堆上的
3.数据段上的

临时对象分类:
显式生成临时对象:
CGoods c3 = CGoods(“可乐”,9,6.6);
//这里指定了临时对象类型是CGoods了

隐式生成临时对象:
c3 = 99.8;
//没有指定类型,先隐式生成临时对象,临时对象赋值给c3,析构临时对象

参数中const的含义: 重点
内置类型产生的临时量:都是常量,不能被改变
自定义类型产生的临时量:都是变量,可以被修改

所以函数形参是:const CGoods &src
含义1:防止实参是个常量,因为常量需要用常引用来引用;
含义2:防止修改实参的值。

int main()
{
	CGoods c1("苹果", 10, 8.9);
	CGoods c2("香蕉", 11, 9.8);
	CGoods c3 = CGoods("可乐",9,6.6);
	//显式的生成临时对象,用临时对象拷贝构造c3,然后临时对象析构
	return 0;
}

C++编译器的优化: 重点
用临时对象构造同类型的新对象时,临时对象不生成,而是用生成临时对象的方式直接构造目标对象

	CGoods c3 = CGoods("可乐",9,6.6);
	这里临时对象是:CGoods("可乐",9,6.6)
	目标对象是:CGoods c3 

	理论上:
	先产生临时对象,然后用临时对象拷贝构造c3对象,然后析构临时对象,期间三次函数调用
	实际上编译器优化后:
	这个临时对象不产生,而是用产生临时对象的方式直接构造新对象c3,所以只调用一次构造函数

综上所述:
我们不要先定义,后赋值来产生一个新对象,直接定义的方式来产生新对象;
即用: CGoods c3 = CGoods(“可乐”,9,6.6);
而不是:
CGoods c3;
c3 = CGoods(“可乐”,9,6.6);
(赋值时,这个临时对象一定产生,不然拿什么赋!!!),所以不要这样写。

对比一下这两个过程:

CGoods c3 = CGoods("可乐",9,6.6);
过程:
使用生成临时对象的方式构造c3对象,调用一次构造函数,临时对象不生成

CGoods c3;
c3 = CGoods("可乐",9,6.6);
过程:
调用默认的构造函数生成c3
生成一个临时对象CGoods("可乐",9,6.6)
临时对象赋值给c3 ,这里调用赋值运算符重载函数
临时对象析构

指针和引用呢?
1.临时对象被引用时,生命周期被提升,语句结束,临时对象生命周期被提升,所以不析构,引用变量什么时候结束,这个对象什么时候结束;
2.不要用指针指向一个临时对象,临时对象语句结束,将被析构。

CGoods * p = &CGoods("可乐",9,6.6);
过程:
构造临时对象
析构临时对象

CGoods &q = CGoods("可乐",9,6.6);
过程:
临时对象生成,但是并不析构
(临时对象被引用时,生命周期被提升)

举个例子:需要注意一下,语句作用域问题

void test (CGoods *p)
{
	cout<<"call test"<<endl;
}
int main()
{
	test(&CGoods("雪碧",8,6.4))
}
执行结果:
call test

临时量出了作用域才被析构,但是这条语句包含函数调用,所以函数调用结束 语句才结束

关键字explict:禁止隐式对象生成,只能显式的生成对象,加载构造函数前。

二、一道例题说明各种对象的生命周期:

class Test
{
public:

	Test(int a = 10, int b = 10)
	{
	}
	~Test()
	{
	}
	Test(const Test &src)
	{
		ma = src.ma;
		mb = src.mb;
	}
	void operator=(const Test &src)
	{
		if (this == &src)
			return;
		ma = src.ma;
		mb = src.mb;
	}
private:
	int ma;
	int mb;

};



Test t1(20,20);   //构造函数
int main()
{
	Test  t2(20,30);  //构造函数
	Test  t3 = t2;  //拷贝构造函数
	static Test t4 = Test (40,40);// 构造函数
	
	t2 = Test (50,50);   //构造函数   赋值运算符重载   析构函数
	t2 = (Test)(60,60);/ /构造函数   赋值运算符重载   析构函数
	t2 = 70;               / /一个参数的构造函数   赋值运算符重载   析构函数

	Test  *p1 = &Test(80,80);//生成临时对象,临时对象析构
	Test &q1 = Test(90,90);  //生成临时对象,不析构,引用生命周期提升
	 
	 Test  *p2 = new Test ;  //构造函数
	 delete p2;                      //析构函数
}
Test  t5 (100,100);           //构造函数

构造顺序:

t1  t5  t2 t3  q1  p2

1.数据段的最后析构,生命周期和程序一样
2.栈上的对象先构造的后析构,出作用域析构
3.堆上的手动开辟,需要手动释放delete析构

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值