C++函数按引用传值与值传值分析

本文是学习《Effective C++》的笔记,记录函数引用传值与值传值在效率上面的区别。

1.效率分析

考虑以下代码:

class Fruit
{
public:
	virtual void ShowName()const;
private:
	std::string strName;
};
class Apple:public Fruit
{
public:
	virtual void ShowName() const;
private:
	std::string strArea;
};
void PrintFruitName(Apple apple)
{
	// do something
}

int main(int argc, char* argv[])
{
	Apple apple;
	PrintFruitName(apple);
	return 0;
}

首先创建Apple对象,然后函数PrintFruitName(Apple apple)以值传递参数,将实参转化为形参,会以apple为蓝本调用Apple的拷贝构造函数,依次构造基类Fruit的std::string成员对象strName,基类Fruit对象,子类Apple的std::string成员对象strArea以及子类Apple自身。

函数PrintFruitName执行完成后,会按照构造顺序的相反顺序依次析构子类Apple,Apple成员是std::string对象,基类Fruit,Fruit的std::string对象,也就是执行此函数会造成四次构造与四次析构函数的调用。

当以引用传值时:

void PrintFruitName(const Apple& apple)
{
	// do something
}

没有任何构造函数与析构函数调用,效率会高很多,这里的const也是十分必要的,原先以值传递Apple对象,PrintFruitName函数也只能对其副本形参进行修改,不会影响传入的参数。现在是const Apple& 引用传参,则用const关键字明确告诉调用者函数不会改变传入的Apple参数,并且提升效率,和按值传递达到一样的效果。

2.对象切割问题

首先分析以下这段代码的输出结果:

#include <iostream>

class Fruit
{
public:
	virtual void ShowName()const;
private:
	std::string strName;
};

void Fruit::ShowName()const
{
	std::cout << "Fruit!!!" << std::endl;
}

class Apple:public Fruit
{
public:
	virtual void ShowName() const;
};

void Apple::ShowName() const
{
	std::cout << "Apple!!!" << std::endl;
}

void PrintFruitName(Fruit fruit)
{
	fruit.ShowName();
}

int main(int argc, char* argv[])
{
	Apple apple;
	PrintFruitName(apple);
	return 0;
}

基础不扎实的我认为由于多态,子类对象转化为基类对象,执行虚函数时会调用子类的函数实现,会输出 “Apple!!!”
VS2019的输出结果为:
在这里插入图片描述
What!!!怎么和想得不一样?
果然我的基础不够扎实,原来以值传递参数会产生对象的切割问题,当子类对象Apple,传递给PrintFruitName(Fruit fruit)时,要调用fruit的拷贝构造函数,即:Fruit(apple),以子类对象拷贝构造基类对象,造成子类Apple的特化性质被切割掉,仅仅留下基类Fruit对象。
这是由于函数形参真正是由Fruit的copy构造函数构造了它, 在调用opy构造函数Fruit(apple)时仅仅以apple的基类部分来构造Fruit。所以形参仅仅表现为基类的性质,不存在多态,所以输出"Furit!!!"。
改成以引用传值,则和预想一直,输出"Apple !!!"

void PrintFruitName(const Fruit& fruit)
{
	fruit.ShowName();
}

3.内置数据类型

而对于内置数据类型,迭代器,函数对象都习惯被设计为用值传递。

4.结论

函数传参时尽量以引用传值代替值传值,以引用传值比值传值更加高效,并且可以避免切割问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值