C++运算符重载引用传参与返回引用的小小心得
1 #include <bits/stdc++.h>
2
3 using namespace std;
4
5 //平面向量类,提供完成向量运算和比较的API
6 //除递增运算符和左移运算符重载外其他函数省略
7
8 class Vec2D
9 {
10 //形参cout和函数返回值使用引用是为了保证拷贝构造函数的调用,以确保全局cout对象唯一
11 //形参vec使用引用是为了提高函数调用效率,也可以不用
12 friend ostream& operator<<(ostream& cout, Vec2D& v); //重载<<运算符
13
14 public:
15 Vec2D(double x, double y); //有参构造函数
16 Vec2D& operator++(); //重载前置++运算符
17 Vec2D operator++(int); //重载后置++运算符
18
19 private:
20 double _x;
21 double _y;
22
23 };
24
25 ostream& operator<<(ostream& cout, Vec2D& v)
26 {
27 cout << '(' << v._x << ',' << v._y << ')' << endl;
28 return cout;
29 }
30
31 Vec2D::Vec2D(double x, double y)
32 {
33 _x = x;
34 _y = y;
35 }
36
37 Vec2D& Vec2D::operator++()
38 {
39 this->_x++;
40 this->_y++;
41 return *this;
42 }
43
44 Vec2D Vec2D::operator++(int)
45 {
46 Vec2D pre = *this;
47 this->_x++;
48 this->_y++;
49 return pre;
50 }
51
52 void test01()
53 {
54 Vec2D v1{ 1, 1 };
55 cout << ++v1 << endl;
56 //cout << v1++ << endl;
57 }
58
59 int main()
60 {
61 test01();
62 return 0;
63 }
我在初学时遇到的一个问题是:重载后置++运算符时,应不应当返回对象的引用?
首先须明确,若令pre = *this,返回引用一定是错误的,因为这是一个开辟在栈内的局部对象,生命周期在成员函数内部,函数结束内存就被释放了;而引用本质是利用指针常量操作对象,利用指针操作不存在的内存是危险的。
其次,若想返回引用,须使用pre = new Vec2D(this->_x, this->_y),这是开辟在堆内的,因此可以安全返回其地址。但与之而来的问题是后续无法对其delete,容易造成内存泄漏。
因此,直接返回对象本身最为妥当,尽管会因此隐式调用一次拷贝构造函数。
与之而来的是第二个问题:代码中注释掉的一行cout << v1++ << endl,会报错:“没有与这些操作数匹配的‘<<’运算符”。
这是因为在定义<<重载时为了提高函数调用运行效率传递对象时,采取了传址调用(引用),而既然需要解引用,就要求实参必须是可以解引用的值,即左值;
而后置++运算符重载返回了一个局部对象,这是一个右值,不能作为左值,所以会报错;
修改方法有二:
(1)把<<运算符重载的形参v修改为传值调用,这样既可以传入一个右值了;
(2)在形参前加上const修饰,即:
friend ostream& operator<<(ostream& cout, const Vec2D& v);
这是因为当const
修饰一个左值引用(型如const Type &
)时,表示该左值引用既可以引用一个左值,也可以引用一个右值(字面值或临时对象),而不带 const
修饰的左值引用(型如Type &
)只能引用一个左值,不能引用一个右值。
C++运算符重载引用传参与返回引用的小小心得的更多相关文章
- 引用传参与reference_wrapper
本文是<functional>系列的第3篇. 引用传参 我有一个函数: void modify(int& i) { ++i; } 因为参数类型是int&,所以函数能够修改传 ...
- ES6中generator传参与返回值
先看两个例子, 1, function* f() { for(var i=0; true; i++) { var reset = yield i; if(reset) { i = -1; } } } ...
- main函数的传参与返回
1.谁给main函数传参(1)调用main函数所在的程序的它的父进程给main函数传参,并且接收main的返回值.2.为什么需要给main函数传参(1)首先,main函数不传参是可以的,也就是说父进程 ...
- C++ 重载运算符返回值 和 返回引用的原因
原因是: +,-,*等返回不了引用,比如+运算符,可以如下重载(为了简单,假设A 只有int x:int y) A operator+(A a,A b) {A sum; sum.x=a.x+b.x ...
- 《挑战30天C++入门极限》C++运算符重载函数基础及其值返回状态
C++运算符重载函数基础及其值返回状态 运算符重载是C++的重要组成部分,它可以让程序更加的简单易懂,简单的运算符使用可以使复杂函数的理解更直观. 对于普通对象来说我们很自然的会频繁使用算数运 ...
- C++二级指针和指针引用传参
前提 一级指针和引用 已经清晰一级指针和引用. 可参考:指针和引用与及指针常量和常量指针 或查阅其他资料. 一级指针和二级指针 个人觉得文字描述比较难读懂,直接看代码运行结果分析好些,如果想看文字分析 ...
- C++基本之 运算符重载
=====>友元运算符#include <iostream> using namespace std; class Test { public: Test(int a = 0) { ...
- C++初阶(运算符重载汇总+实例)
运算重载符 概念: 运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似. 函数原型: 返回值 operator操作符(参数列表) 注意: ...
- C++程序设计方法3:数组下标运算符重载
数组下标运算符重载 函数声明形式 返回类型operator[](参数): 如果返回类型是引用,则数组运算符调用可以出现在等式的左边,接受赋值,即: Obj[index] = value; 如果返回类型 ...
- 《挑战30天C++入门极限》对C++递增(增量)运算符重载的思考
对C++递增(增量)运算符重载的思考 在前面的章节中我们已经接触过递增运算符的重载,那时候我们并没有区分前递增与后递增的差别,在通常情况下我们是分别不出++a与a++的差别的,但的确他们直接是 ...
随机推荐
- SVN: E155004: THERE ARE UNFINISHED WORK ITEMS IN ''; RUN 'SVN CLEANUP' FIRST
eclipse的SVN更新或者还原都报错 使用clean up也不好用 解决办法 通过网址https://www.sqlite.org/download.html下载这个软件 解压放到.svn文件夹下 ...
- boolean布尔型盲注
mysql中limit的详细用法 1.用于强制返回指定的记录行数 在查询中,经常要返回前几条或者中间某几行数据时,用到limit 语法如下 select * from table_name limit ...
- 【git】git子模块操作-从子模块的远端拉取上游修改 & 从项目远端拉取更改
1.从子模块的远端拉取上游修改 1.1 在项目子模块目录中,运行git fetch与git merge更新本地代码 (1) 这种方法在获取子模块非master分支的更新时,没成功获取更新,没搞清楚原因 ...
- unity 2D 物体跟随鼠标旋转 移动
using System.Collections; using System.Collections.Generic; using UnityEngine; public class FollowMo ...
- asp.net core 解决用户上传文件提示 System.UnauthorizedAccessException: Access to the path 'C:\Windows\TEMP\ASPNETCORE_e65c14f7-e337-493c-90ac-d49a48db7187.tmp' is denied.
今天发布项目到服务器 上传文件突然提示 System.UnauthorizedAccessException: Access to the path 'C:\Windows\TEMP\ASPNETCO ...
- 如何基于ZK实现高可用架构
zookeeper设计步骤 设计path 节点的路径 选择znode类型 普通节点.临时节点等 设计znode数据 节点中的数据 设计watch 节点的监听事件以及对应的处理 ZK实现主备切换架构 ...
- python manage.py loaddata dumpdata 用于导出和导入数据库中的数据
1.数据导出python manage.py dumpdata python manage.py dumpdata [appname] > appname_data.json 指定appna ...
- HTML学习笔记6----链接
随笔记录方便自己和同路人查阅. #------------------------------------------------我是可耻的分割线--------------------------- ...
- vscode 部分替换(正则替换)
1. 数字 \d{n} 2. 数字和字母 [A-Za-z0-9]{n} 常用运算符与表达式 ^ 开始 () 域段 [] 包含,默认是一个字符长度 [^] 不包含,默认是一个字符长度 {n,m} 匹配长 ...
- vue中标签的替换以及scoped实现css对当前文件起作用的原理
1,vue的工作原理其实就是我们前端拿到组件模板(也就是编译打包后生成的js文件,由vue动态生成html标签以及异步请求服务器的数据,更新html页面展示给用户) 如上图所示,public文件夹下的 ...