C++中参数传递方式讨论

C++笔记之两个类的实例之间传递参数的各种方法 在 C++ 中,没有内置的事件系统,但你可以模拟一个简单的事件系统来在两个类的实例之间传递参数。这个例子演示了如何使用观察者模式在两个类的实例之间传递参数,其中一个类充当主题(Subject),而另一个类充当观察者(Observer)。在 C++ 中,使用消息传递机制来在两个类的实例之间传递参数可以通过使用事件系统、消息队列、观察者模式等方式来实现。这个例子演示了如何使用简单的事件系统来模拟消息传递机制,在两个类的实例之间传递参数。这个例子演示了如何模拟一个简单的事件系统,在两个类的实例之间传递参数。 阅读详情

众所周知,在C++中调用函数时有三种参数传递方式:
(1)传值调用;
(2)传址调用(传指针);
(3)引用传递;
实际上,还有一种参数传递方式,就是全局变量传递方式。这里的“全局”变量并不见得就是真正的全局的,所有代码都可以直接访问的,只要这个变量的作用域足够这两个函数访问就可以了,比如一个类中的两个成员函数可以使用一个成员变量实现参数传递,或者使用static关键字定义,或者使用namespace进行限制等,而这里的成员变量在这种意义上就可以称作是“全局”变量(暂时还没有其它比“全局”更好的词来描述)。当然,可以使用一个类外的真正的全局变量来实现参数传递,但有时并没有必要,从工程上讲,作用域越小越好。这种方式有什么优点呢?
效率高!
的确,这种效率是所有参数传递方式中效率最高的,比前面三种方式都要高,无论在什么情况下。但这种方式有一个致命的弱点,那就是对多线程的支持不好,如果两个进程同时调用同一个函数,而通过全局变量进行传递参数,该函数就不能够总是得到想要的结果。

下面再分别讨论上面三种函数传递方式。
1. 从功能上。按值传递在传递的时候,实参被复制了一份,然后在函数体内使用,函数体内修改参数变量时修改的是实参的一份拷贝,而实参本身是没有改变的,所以如果想在调用的函数中修改实参的值,使用值传递是不能达到目的的,这时只能使用引用或指针传递。例如,要实现两个数值交换。
void swap(int a, int b);
void main(){
    int a=1, b=2;
    swap(a,b);
}
这样,在main()函数中的a,b值实际上并没有交换,如果想要交换只能使用指针传递或引用传递,如:
void swap(int* pa, int* pb);
或
void swap(int& ra, int& rb);

2.从传递效率上。这里所说传递效率,是说调用被调函数的代码将实参传递到被调函数体内的过程,正如上面代码中,这个过程就是函数main()中的a,b传递到函数swap()中的过程。这个效率不能一概而论。对于内建的int, char,  short,long,float等4字节或以下的数据类型而言,实际上传递时也只需要传递1-4个字节,而使用指针传递时在32位CPU中传递的是32位的指针,4个字节,都是一条指令,这种情况下值传递和指针传递的效率是一样的,而传递double, long long等8字节的数据时,在32位CPU中,其传值效率比传递指针要慢,因为8个字节需要2次取完。而在64位的CPU上,传值和传址的效率是一样的。再说引用传递,这个要看编译器具体实现,引用传递最显然的实现方式是使用指针,这种情况下与指针的效率是一样的,而有些情况下编译器是可以优化的,采用直接寻址的方式,这种情况下,效率比传值调用和传址调用都要快,与上面说的采用全局变量方式传递的效率相当。
    再说自定义的数据类型,class, struct定义的数据类型。这些数据类型在进行传值调用时生成临时对象会执行构造函数,而且当临时对象销毁时会执行析构函数,如果构造函数和析构函数执行的任务比较多,或者传递的对象尺寸比较大,那么传值调用的消耗就比较大。这种情况下,采用传址调用和采用传引用调用的效率大多数下相当,正如上面所说,某些情况下引用传递可能被优化,总体效率稍高于传址调用。
3. 从执行效率上讲。这里所说的执行效率,是指在被调用的函数体内执行时的效率。因为传值调用时,当值被传到函数体内,临时对象生成以后,所有的执行任务都是通过直接寻址的方式执行的,而指针和大多数情况下的引用则是以间接寻址的方式执行的,所以实际的执行效率会比传值调用要低。如果函数体内对参数传过来的变量进行操作比较频繁,执行总次数又多的情况下,传址调用和大多数情况下的引用参数传递会造成比较明显的执行效率损失。

综合2、3两种情况,具体的执行效率要结合实际情况,通过比较传递过程的资源消耗和执行函数体消耗之和来选择哪种情况比较合适。而就引用传递和指针传递的效率上比,引用传递的效率始终不低于指针传递,所以从这种意义上讲,在C++中进行参数传递时优先使用引用传递而不是指针。

4. 从类型安全上讲。值传递与引用传递在参数传递过程中都执行强类型检查,而指针传递的类型检查较弱,特别地,如果参数被声明为 void* ,那么它基本上没有类型检查,只要是指针,编译器就认为是合法的,所以这给BUG的产生制造了机会,使程序的健壮性稍差,如果没有必要,就使用值传递和引用传递,最好不用指针传递,更好地利用编译器的类型检查,使得我们有更少的出错机会,以增加代码的健壮性。
这里有个特殊情况,就是对于多态的情况,如果形参是父类,而实参是子类,在进行值传递的时候,临时对象构造时只会构造父类的部分,是一个纯粹的父类对象,而不会构造子类的任何特有的部分,因为办有虚的析构函数,而没有虚的构造函数,这一点是要注意的。如果想在被调函数中通过调用虚函数获得一些子类特有的行为,这是不能实现的。

5. 从参数检查上讲。一个健壮的函数,总会对传递来的参数进行参数检查,保证输入数据的合法性,以防止对数据的破坏并且更好地控制程序按期望的方向运行,在这种情况下使用值传递比使用指针传递要安全得多,因为你不可能传一个不存在的值给值参数或引用参数,而使用指针就可能,很可能传来的是一个非法的地址(没有初始化,指向已经delete掉的对象的指针等)。所以使用值传递和引用传递会使你的代码更健壮,具体是使用引用还是使用,最简单的一个原则就是看传递的是不是内建的数据类型,对内建的数据类型优先使用值传递,而对于自定义的数据类型,特别是传递较大的对象,那么请使用引用传递。

6. 从灵活性上。无疑,指针是最灵活的,因为指针除了可以像值传递和引用传递那样传递一个特定类型的对象外,还可以传递空指针,不传递任何对象。指针的这种优点使它大有用武之地,比如标准库里的time( )函数,你可以传递一个指针给它,把时间值填到指定的地址,你也可以传递一个空指针而只要返回值。

综合以上几种传递方式,列表如下,方便不同情况下选择合适的传递方式。我们将各种指标分高、中、低三个级,别处于同一级别的两种方式,表示这两种方式是等效的。

传递方式功能传递效率
内嵌/自定义
执行效率
类型安全参数检查灵活性多线程
全局变量高高 / 高高 高高低低
值低高 / 低高 中高中高
指针高低 / 中低低低高中
引用高中 / 高中高高中中

以上讨论了四种参数传递方式的优缺点,下面再讨论一下在参数传递过程中一些共同的有用的技术。

1. const关键字。当你的参数是作为输入参数时,你总不希望你的输入参数被修改,否则有可能产生逻辑错误,这时可以在声明函数时在参数前加上const关键字,防止在实现时意外修改函数输入,对于使用你的代码的程序员也可以告诉他们这个参数是输入,而不加const关键字的参数也可能是输出。例如strlen,你可以这样声明
    int strlen(char* str);
功能上肯定没有什么问题,但是你想告诉使用该函数的人,参数str是一个输入参数,它指向的数据是不能被修改的,这也是他们期望的,总不会有人希望在请人给他数钱的时候,里面有张100的变成10块的了,或者真钞变成假钞了,他们希望有一个保证,说该函数不会破坏你的任何数据,声明按如下方式便可让他们放心:
    int strlen(const char* str);
可不可以给str本身也加一个限制呢,如果把地址改了数得的结果不就错了吗?总得给人点儿自由吧,只要它帮你数钱就行了,何必介意他怎么数呢?只要不破坏你的钱就OK了,如果给str一个限制,就会出现问题了,按照上面的声明,可以这样实现:
  int strlen(const char* str)
{    int cnt;
if( !str) return 0;
     cnt = 0;
     while( *(str++) ){
        ++cnt;
    }
    return cnt;
}
可是,如果你硬要把声明改成
    int strlen(const char* const str);
上面的函数肯定就运行不了了,只能改用其它的实现方式,但这个不是太有必要。只要我们保护好我们的钱就行了,如果它数不对,下次我次不让它数,再换个人就是了。

对于成员函数,如果我们要显示给客户代码说某个成员函数不会修改该对象的值,只会读取某些内容,也可以在该函数声明中加一个const.
clas    Person
{......
  public:
    unsigned char Age( void ) const;  // 看到const就放心了,这个函数肯定不会修改m_age
  private:
    unsigned char m_age;   // 我认为这个类型已经足够长了,如果觉得不改可以改为unsigned long
}

    2. 默认值。个人认为给参数添加一个默认值是一个很方便的特性,非常好用,这样你就可以定义一个具有好几个参数的函数,然后给那些不常用的参数一些默认值,客户代码如果认为那些默认值正是他们想要的,调用函数时只需要填一些必要的实参就行了,非常方便,这样就省去了重载好几个函数的麻烦。可是我不明白c#为什么把这个特性给去掉了,可能是为了安全,这样就要求每次调用函数时都要显示地给函数赋实参。所以要注意,这可是个双刃剑,如果想用使刀的招跟对手武斗,很可能伤到自己。

    3.参数顺序。当同个函数名有不同参数时,如果有相同的参数尽量要把参数放在同一位置上,以方便客户端代码。

C++笔记之两个类的实例之间传递参数——通过构造函数传递类对象的方法详细探究 【代码】C++笔记之两个类的实例之间传递参数——通过构造函数传递类对象的方法详细探究。 阅读详情

相关推荐

浅谈C++函数的参数传递方式

通常情况下,传值方式适用于简单数据类型、指针适用于需要修改实参的指针类型、引用适用于需要修改实参的非指针类型、const引用适用于需要引用大型结构体或对象。此外,传值方式还有一个缺点,就是当参数类型为大型结构体或对象时,传递的副本会占用更多的内存,导致程序效率下降。在swap函数中,通过指针访问实参x和y的值,交换它们的值。当函数调用时,形参会创建一个副本,复制实参的值,函数内部操作的是这个副本,不会影响到原实参。引用的含义是,在函数内部,形参引用实参的内存空间,对引用变量的修改会影响到实参本身。

CyberWarpX的博客 101

值传递与引用传递的区别

一、值传递:是指在调用函数时将s实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。 ​ 代码在内存中的执行流程: 1、首先加载main方法; ​ 2、接下来int number = 100; ​ 3、输出调用前的number,结果为100; ​ 4、调用change方法; ​ 5、在change方法中传参,传的是number,值为100; ​ 6、在change方法中对其number修改其值为200; ​ 虽然方法中的numb...

mengfanshaoxia的博客 1万+

Win11系统重装全记录:从备份Office激活到搞定RAID阵列,我的微星笔记本复活记

本文详细记录了Win11系统重装的完整过程,从数据备份到RAID阵列配置,特别针对微星笔记本的特殊硬件驱动问题提供了解决方案。文章涵盖了Office激活状态备份、BIOS设置、驱动安装顺序等关键步骤,帮助用户顺利完成系统重装并优化性能。

weixin_31421613的博客 309

【c++基础】多态/虚函数:父类为形参,子类为实参时的传参情况

多态,虚函数/纯虚函数

All_In_gzx_cc的博客 4200

电子系统设计与创新实践作品:简易电子琴

题目 4:简易电子琴 (1)具有8个音阶按键,每个音阶按键频率如表1所示。 (2)每个按键对应LED显示。 (3)音阶信号经功放连接8欧姆扬声器,输出功率可达1W。 (4)每个音阶输出音量一样。 (5)扬声器输出音量可调节,音量调节分为高、中、低三档,并进行档位显示。

weixin_47510497的博客 2858

注册电气工程师详细教材

注册电气工程师详细教材

qq_40844444的博客 4257

在 C++ 中将函数作为参数传递

将函数作为参数传递是 C++ 中的一个有用概念。在将自定义比较器函数作为std::sort()中的参数传递 以根据需要对对象序列进行排序时,已经使用了这个概念。在本文中,我们将讨论设计接受另一个函数作为参数的函数的不同方法。使用函数的想法是一起执行一些常见或重复完成的任务并创建一个函数,这样就不必为不同的输入一次又一次地编写相同的代码。在C++ 11中,有一个std::function<> 模板类,允许将函数作为对象传递。std::function<> 的对象可以 按如下方式创建。

我的博客,不一样的自我表达 2434

SMIC Memory配置与Library Compiler实战:从lib到db的高效转换

本文详细介绍了SMIC Memory Compiler的配置要点与使用Library Compiler将.lib文件高效转换为.db文件的完整流程。文章深入解析了关键配置参数对性能和面积的影响,并提供了从交互式操作到自动化脚本的实战指南,帮助数字芯片设计工程师顺利完成存储器模型的生成与集成,确保Design Compiler能正确调用。

weixin_28314575的博客 336

C++函数参数与参数传递

- 参数传递是指用函数调用的实参来初始化函数形参存储区的过程 - 函数的形参是局部对象,仅仅下函数的作用域内可见 - 每次调用函数时,会创建形参变量,并用传入的实参初始化形参

ONE_TEA的博客 746

PPT制作能力在职场中真的重要吗?一定要美术功底才能学好PPT吗?

我推出PPT技能培训专栏啦!好的PPT可以让你事半功倍、2023拥有PPT能力还可以让你具备一门极有价值的斜杠能力。更多内容请进:梦幻训练营专栏。专栏内会用本人积累的近10年的PPT学习方法论在短时间内教会你如何制作出精美绝伦的PPT,每篇教程后还会免费赠送一些小福利,不可多得。

打造全国最全的AI Agent开发知识领域的博客 728

在 LangGraph 中集成 Skills 增强智能体能力

LangGraph 的核心是通过**状态机 + 节点(Node) + 工具(Tool)**来编排智能体流程,你可以把 Skills 理解为“封装好的工具或可复用的任务流”,下面是一套可落地的集成方案。

lpfasd123的博客 1180

C++学习——指针、引用、参数传递

本文总结了一些C++学习与面试题常考的重点知识,包含指针、引用、参数传递等相关内容。

mingyuexin235的博客 2011

基于STM32+华为云设计的智能鱼缸

本项目基于STM32单片机设计一款基于物联网的智能鱼缸系统,并通过应用侧接口开发上位机APP实现远程对鱼缸参数的检测和控制。该系统包括水温检测、水质检测、自动或手动换水、氛围灯灯光变换和自动或手动喂食等功能,可以帮助用户更好地管理鱼缸,提高鱼儿的生存率,同时增强用户对家庭装饰品的掌控感和科技感。

1万+

c++ 参数传递机制

C++的参数传递机制&nbsp;C++一共有三种传递方式:值传递(pass by value)、指针传递(pass by pointer)、引用传递(pass by reference)。关键点:在函数中,编译器总是要为函数的每个参数制作临时副本。引用传递除外。 一.值传递。值传递很简单。唯一要注意的就是当值传递的输入参数是用户自定义类型时,最好用引用传递代替,并加上const关键字。因为引用...

David 1552

【定位模块项目实战】gnss_localizer、lidar_localizer功能包解析

系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 TODO:写完再整理 文章目录系列文章目录前言一、1.2.3.4.二、1.2.3.4.三、1.2.3.4.四、1.2.3.4.总结参考资料 前言 认知有限,望大家多多包涵,有什么问题也希望能够与大家多交流,共同成长! 本文先对**【无人驾驶autoware项目实战】感知–定位模块**做个简单的介绍,具体内容后续再更,其他模块可以参考去我其他文章 提示:以下是本篇文章正文内容 一、 1. 2. 3. 4. . . 二、

qq_35635374的博客 1931

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

C++函数的参数传递机制以及参数的类型选择

C++primer之函数的参数传递以及参数的类型 一:函数的基本知识 (1)      函数要素:返回类型,函数名字,形参(参数之间用逗号隔开) (2)      函数调用机制:我们通过调用运算符来执行函数,其中运算符就是括号 (3)      当我们调用函数时,主调函数被暂停执行,被调函数开始执行,当被调函数遇到return语句时,return语句完成两项工作,1:返回

追尋ゝ 2496

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

c++ max函数_「C/C++」函数:定义、调用、参数传递

5.1基本概念函数分为主函数和子函数,一个程序中主函数有且只有一个,是程序的入口,而函数(或称子函数)可以有很多。子函数的存在可以让主函数不臃肿、一目了然,增强代码可读性。引入函数的意义:利用率高,可读性强,利于移植前文介绍介绍过变量的作用域,跨函数传递参数,不会改变变量作用域,一般只是把主函数中的实参传递给了子函数中的形参,子函数处理后再return一个值。5.1.1定义在main函数前,直接定...

weixin_39710295的博客 2154

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

c++传址调用_C++中的参数传递方式:传值、传地址、传引用总结

技术交流QQ群:1027579432,欢迎你的加入!指针:指针是一个变量,只不过这个变量中存储的是一个地址,指向内存中的一个单元。引用:引用和原变量是同一个东西,只不过是原变量的一个别名。int a = 10; 定义一个整型变量aint *p = &a; 定义一个指向整型变量的指针变量p,该指针指向a的存储单元,即p的值是a存储单元的地址int &b = a; 定义一个整型...

weixin_34221892的博客 966

C++ 11 之 参数传递

c11参数传递.cpp。

LSG_Dawn的博客 192

CPP----C++常识100例

C++基础知识

writ的博客 1576
上一篇: C++操作符重载(小原则)
下一篇: VC++ Windows平台字符透明编程大总结
barryxt
博客等级 码龄19年 18粉丝 8原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值