IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++学习第十九课--临时对象深入探讨、解析与提高性能手段笔记 -> 正文阅读

[C++知识库]C++学习第十九课--临时对象深入探讨、解析与提高性能手段笔记

一、以传值的方式给函数传递参数

在讲解临时对象时,尽量让大家感知到临时对象的存在,所以通过写程序演示对临时对象进行说明。

在工程中创建两个文件,rectangle.h和rectangle.cpp文件。

在rectangle.h头文件中这样声明:

#include <iostream>
#include<string.h>

using namespace std;

class rectangle //长方形类
{
public:
	int length;//长方形的长
	int width; //长方形的宽
public:
	rectangle(int length=0,int width=0);//带参构造函数
	rectangle(const rectangle &rect);   //拷贝构造函数
	virtual ~rectangle();//虚析构函数
public:
	int Area(rectangle rect);//成员函数
};

#endif // !__STUDENT_H__

在rectangle.cpp文件中这样定义:

#include"rectangle.h"

using namespace std;

rectangle::rectangle(int length, int width):length(length),width(width)
{
	cout << "调用了构造函数!" << endl;
}

rectangle::rectangle(const rectangle& rect) :length(rect.length), width(rect.width)
{
	cout << "调用了拷贝构造函数!" << endl;
}

rectangle::~rectangle()
{
	cout << "调用了析构函数!" << endl;
}

int rectangle::Area(rectangle rect)
{
	int temp = rect.length * rect.width;
    rect.length = 255;
	return temp;
}

在main函数中这样调用:

int main()
{
	rectangle rtg(10,20);
	
	cout << "rtg.length = " << rtg.length << endl;
	cout << "rtg.width  = " << rtg.width << endl;

	int areaValue = rtg.Area(rtg);
	cout << "areaValue  = " << areaValue << endl;

	return 0;
}

运行结果如下所示:

?可以看到:

程序运行结果调用了拷贝构造函数,因为在调用Area成员函数时把对象rtg传递给了Area成员函数,此时,系统调用拷贝构造函数创建一个副本rtg,用于函数体Area内使用。rtg仅是一个局部对象,只能在Area函数体中使用,rtg是一个假临时对象,不过,代码生成程序rtg对象,调用了构造函数,有了复制的动作,就会影响程序执行效率。

为了提高程序执行效率,在声明和定义中,把对象修改为引用。程序修改如下,

rectangle.h头文件声明修改如下:

int Area(rectangle &rect);//成员函数

rectangle.cpp文件定义修改如下:

int rectangle::Area(rectangle &rect)
{
	int temp = rect.length * rect.width;
	return temp;
}

运行程序,结果如下:

?可以看到:

程序在执行的过程中,少了一次调用拷贝构造函数和析构函数(如果这个类时子类,且不用引用,父类的拷贝构造函数也会执行,会降低程序执行效率)。

二、类型转换生产的临时对象/隐式类型转换以保证函数调用成功

在main主函数中写如下代码:

rectangle rtg;
cout <<"rtg.length = " << rtg.length << endl;
cout <<"rtg.width = "<< rtg.width << endl;

rtg = 1000;
cout << "rtg.length = " << rtg.length << endl;
cout << "rtg.width = " << rtg.width << endl;

运行程序结果显示如下:

可以看到:

构造函数调用了两次,析构函数也调用了两次。

问题原因:

系统执行rtg=1000,这行代码系统做的事情,

(1)用1000这个数字创建了一个类型为rectangle?的临时对象;

(2)调用拷贝构造函数运算符把这临时对象里面的刚刚成员值赋给了rtg对象;

(3)销毁刚刚这个创建的rectangle?的临时对象。

?问题解决:

把“rectangle?rtg;和“rtg =?1000;”优化成一句语句,如下,

rectangle rtg = 1000;
cout <<"rtg.length = " << rtg.length << endl;
cout <<"rtg.width = "<< rtg.width << endl;

运行结果显示如下:

?这样系统就不会产生临时对象,少调用一次构造函数和一次析构函数,提高了程序执行效率。

三、函数返回对象的时候

这是一真的临时对象,因为这个临时对象确实存在,但是从程序代码的角度又无法直接看到它。

在上面的rectangle.h文件的rectangle类外声明一个函数:

rectangle perimeter(rectangle &rect);

rectangle.cpp文件中定义一个函数:

rectangle perimeter(rectangle &rect)
{
   rectangle rtg;//这里会消耗一次构造函数和析构函数调用
   rtg.length  = rect.length*2;
   rtg.width   = rect.length*2;
   return rtg;
}

在main主函数中这样调用:

int main()
{
	rectangle rtg(10,15);
	rectangle rtg1 = perimeter(rtg);
	cout << "rtg.length = " << rtg1.length << endl;
	cout << "rtg.width  = " << rtg1.width << endl;
	return 0;
}

运行结果如下:

可以看到:

构造函数调用2次,拷贝构造函数调用1次,析构函数调用3次,经过调试发现,“rectangle?rtg;”会消耗一次构造函数和析构函数调用。?

解决方法:

优化perimeter函数里面的书写方法,如下,

rectangle perimeter(rectangle& rect)
{
	//方式一
	//rectangle rtg;//这里会消耗一次构造函数和析构函数调用
	//rtg.length = rect.length * 2;
	//rtg.width = rect.width * 2;
	//return rtg;

	//方式二
	return rectangle(rect.length * 2, rect.width * 2);
}

程序优化后再运行程序如下,

?可以看到:

优化的程序减少了一次构造函数和一次析构函数调用。

总结:

在perimeter函数中用rectangle创建对象rtg会产生临时对象,就会调用一次构造函数和一次析构函数。然后执行“return rtg;”(执行return rectangle(rect.length * 2, rect.width * 2);也是一样的)也会产生临时对象调用一次构造函数和一次析构函数,只是这个无法避免。

四、类外的运算符重载之中的优化

这里先介绍一个额外知识点:类外的运算符重载。

之前讲解过双目运算符(“+”)和赋值运算符(“=”),如下,

双目运算符重载:

double Score::operator+(const Score& sc)//重载+号 用于对象相加
{
	return (this->math + sc.math);
}


Score Score::operator+(const int mathSc)//重载+号 用于对象和数值
{
	this->math = this->math + mathSc;
	return *this;
}

赋值运算符重载:

Score Score::operator=(const Score& sc)
{
	math    = sc.math;
	Chinese = sc.Chinese;
	English = sc.English;
	return *this;
}

其实运算符的重载可以不依托与类,也可以写成一个独立的函数,只不过写成的独立函数时,参数有一定的变化。

下面来写一个独立的“+”运算符重载。在.cpp文件中如下书写:

class myNum
{
public:
	myNum()
	{
		cout << "调用了构造函数!" << endl;
	}

	myNum(const myNum& t)
	{
		cout << "调用了拷贝构造函数!" << endl;
	};

	virtual ~myNum()
	{
		cout << "调用了析构函数!" << endl;
	}
public:
	int num1;
	int num2;
};

myNum operator+(myNum&tmpNum1,myNum&tmpNum2)
{
	myNum result;
	result.num1 = tmpNum1.num1 + tmpNum2.num1;
	result.num2 = tmpNum1.num2 + tmpNum2.num2;
	return result;
}

在main主函数中这样写:

int main()
{
	myNum tm1;
	tm1.num1 = 10;
	tm1.num2 = 100;

	myNum tm2;
	tm2.num1 = 20;
	tm2.num2 = 200;

	myNum tm3 = tm1 + tm2;

	return 0;
}

运行结果如下所示:

可以看到:

程序执行了3次构造函数,1次拷贝构造函数和4次析构函数。

?这里重点看operator+这个函数中的代码,其中有一个局部变量的对象result被return出去了,这种函数返回一个对象的情况也会导致产生临时对象。这里operator+必须返回一个对象,这个对象表示两个对象相加的和(而“和”这个对象是局部的,不可能带到外面去,所以编译器肯定会通过生成临时对象来处理结果的返回问题)。

所以,这种临时对象,系统会调用构造函数、拷贝构造函数和析构函数。下面优化方法如下:

(1)修改构造函数

myNum(int x = 0,int y = 0):num1(x),num2(y)
{
    cout<<"调用了构造函数!"<<endl;
}

(2)修改myNum operator+

myNum operator+(myNum&tmpNum1,myNum&tmpNum2)
{	
    return myNum(tmpNum1.num1 + tmpNum2.num1,tmpNum1.num2 + tmpNum2.num2);
}

程序优化后再运行结果如下所示:

可以看到:

程序比上面没有优化之前少调用一次拷贝构造函数和一次析构函数。

?

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-07-20 18:34:21  更:2022-07-20 18:34:31 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:42:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码