c++禁止函数的传值调用的方法
作者:Dabelv 发布时间:2022-12-02 13:35:09
代码编译运行环境:VS2017+Debug+Win32
按照参数形式的不同,C++应该有三种函数调用方式:传值调用、引用调用和指针调用。对于基本数据类型的变量作为实参进行参数传递时,采用传值调用与引用调用和指针调用的效率相差不大。但是,对于类类型来说,传值调用和引用调用之间的区别很大,类对象的尺寸越大,这种差别越大。
传值调用与后面两者的区别在于传值调用在进入函数体之前,会在栈上建立一个实参的副本,而引用和指针调用没有这个动作。建立副本的操作是利用拷贝构造函数进行的。因此,要禁止传值调用,就必须在类的拷贝构造函数上做文章。
可以直接在拷贝构造函数中抛出异常,这样就迫使程序员不能使用拷贝构造函数,否则程序总是出现运行时错误。但是,这不是一个好的办法,应该在编译的阶段就告诉程序员,不能使用该类的拷贝构造函数。
1.不显示定义拷贝构造函数可行吗?
#include <iostream>
using namespace std;
class A
{
public:
int num;
A(){num=5;}
};
void show(A a)
{
cout<<a.num<<endl;
}
int main()
{
A obj;
show(obj);
}
以上程序顺利通过编译,并输出5。因此,不显示定义拷贝构造函数,并不能阻止对类的拷贝构造函数的调用,原因是编译器会自动为没有显示定义拷贝构造函数的类提供一个默认的拷贝构造函数。
2.显示定义拷贝构造函数并将访问权限设置为private
上面的程序添加拷贝构造函数的定义,修改如下。
#include <iostream>
using namespace std;
class A
{
A(const A&){};
public:
int num;
A(){num=5;}
};
void show(A a)
{
cout<<a.num<<endl;
}
int main()
{
A obj;
show(obj);
}
这个程序在VS2017环境下编译不通过,得到如下错误:error C2248: “A::A”: 无法访问 private 成员(在“A”类中声明)。
这样就能阻止了函数调用时,类A的对象以值传递的方式进行函数函数调用。为使程序通过编译,需将show()函数的定义改为如下形式:
void show(const A& a)
{
cout<<a.num<<endl;
}
3.拷贝构造函数的说明
(1)如果将拷贝构造函数中的引用符号去掉&,编译将无法通过,出错的信息如下:非法的复制构造函数: 第一个参数不应是“A”。原因是如果拷贝构造函数中的参数不是一个引用,即形如A(const A a),那么就相当于采用了传值的方式(pass-by-value),而传值的方式会调用该类的拷贝构造函数,从而造成无穷递归地调用拷贝构造函数。因此拷贝构造函数的参数必须是一个引用或一个指针。
(2)拷贝构造函数的参数通常情况下是const的,但是const并不是严格必须的。
(3)附带说明,在下面几种情况下会调用拷贝构造函数:
a. 显式或隐式地用同类型的一个对象来初始化另外一个对象;
b. 作为实参以值传递的方式传递给一个函数;
c. 在函数体内返回一个对象时,也会调用返回值类型的拷贝构造函数;
d. 需要产生一个临时类对象时(类对象作为函数返回值会创建临时对象)。
来源:https://cloud.tencent.com/developer/article/1394325


猜你喜欢
- 传播行为定义关于客户端和被调用方法的事务边界。Spring定义了7种截然不同的传播行为。1,PROPAGATION_MANDATORY,表示
- springboot项目不配置数据源启动报错spring boot默认会加载org.springframework.boot.autocon
- 零、业务逻辑Controller-->service接口-->serviceImpl-->dao接口-->daoIm
- 点击图标进入指定浏览器。只需在onCreate()方法里添加如下代码:String url = "http://tiger-kfp
- 一、简介地图控件自v2.3.5版本起,支持多实例,即开发者可以在一个页面中建立多个地图对象,并且针对这些对象分别操作且不会产生相互干扰。文件
- 1.字符串值中包含E等科学计数法,比如12E-2,需要进行转化为普通数值0.12,2.转化函数如下: private Decima
- jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS
- 本文实例汇总了C#路径,文件,目录及IO常见操作。分享给大家供大家参考。具体如下:问题1:如何判定一个给定的路径是否有效/合法;通过Path
- 1.pom文件示例2.执行mvn package出现异常mvn package3.异常堆栈详细信息[WARNING] Error injec
- 前言前段时间因为工作的需要用到Spring事件,翻翻文档将功能实现了,但是存在少许理解不畅的地方,今天有空来梳理梳理。需求背景叶子同学在新入
- 本文实例讲述了C#内置队列类Queue用法。分享给大家供大家参考。具体分析如下:这里详细演示了C#内置的队列如何进行添加,移除等功能。usi
- 详解Kotlin Android开发中的环境配置在Android Studio上面进行安装插件在Settings ->Plugins
- springboot Interceptor * excludePathPatterns忽略失效excludePathPatterns方法是
- Spring Cloud Gateway(以下简称 SCG)做为网关服务,是其他各服务对外中转站,通过 SCG 进行请求转发。在请求到达真正
- C#调用c++dll文件是一件很麻烦的事情,首先面临的是数据类型转换的问题,相信经常做c#开发的都和我一样把学校的那点c++底子都忘光了吧(
- MyBatis中PageHelper不生效今天使用pageHelper,发现设置了PageHelper.startPage(page, pa
- flutter中的布局flutter布局机制的核心是组件。在flutter中,几乎所有的东西都是组件,布局模型也不例外。图片,Icon, 文
- 之前使用OnSharedPreferenceChangeListener,遇到了点小问题,就是有些时候OnSharedPreferenceC
- Springboot 在普通类型注入Service或mapper最近遇到一个难题(大佬可能感觉这太简单了把),对于我这样的小白来说,确实有些
- 用Visual Studio等IDE写C#的Hello World非常简单,但脱离了IDE你能不能打印出Hello World呢?这不是说工