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++的差别的,但的确他们直接是 ...
随机推荐
- CIL指令和指针类型的操作
对象引用的使用在CIL中受到严格限制.它们几乎完全被使用带有VOS(Virtual Object System)指令,这些指令是专门为处理对象和部分对象引用而设计的. 常规操作如下: 首先我们需要将加 ...
- source insight c++ namespace 无法跳转解决方法
source insight c++ namespace 无法跳转解决方法 2016年02月15日 11:47:35 暗小夜 阅读数:4460 勾选igore namespace declarat ...
- 【git】3.2git分支-分支的新建与合并
资料来源 (1) https://git-scm.com/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%88%86%E6%94%AF%E7%9A%84%E6%96%B0% ...
- win11 改键盘映射
编辑注册表:按下win+r,输入regedit找到这个路径HKEY_LOCAL_MACHINE\ SYSTEM\ CurrentControlSet\ Control\ Keyboard Layout ...
- MySQL Delete 表数据后,磁盘空间并未释放,为什么?
有开发小哥咨询了一个问题,记录一下处理过程分享给有需要的朋友.问题如下:MySQL数据库中有几张表增删比较频繁.数据变动剧烈且数据量大,导致数据增长过快,磁盘占用多.为了节约成本,定期进行数据备份,并 ...
- redis-RedisTemplate.opsForValue 常用方法
16.multiSetIfAbsent(Map<? extends K,? extends V> map) 如果对应的map集合名称不存在,则添加,如果存在则不做修改. Map value ...
- dp泄露
DP泄露 选了三道与RSA的dp泄露有关的题,dp泄露算是比较有辨识度的题型. 目录 DP泄露 原理 ctfshow funnyrsa3 分析 解答 BUUCTF RSA2 分析 解答 [羊城杯 20 ...
- Redis-shake工具 [ 自建redis集群->云redis主从 ]
redis-shake工具是阿里用go写的开源工具 开始前准备 1. 确保ECS实例与Redis实例属于同一专有网络(即实例基本信息中的专有网络ID一致) 2. 获取ECS实例的内网IP地址,即执行操 ...
- 简单的python线程池实现线程安全demo
from concurrent.futures import ThreadPoolExecutor import threading import time import sys sys.path.a ...
- File类的基本用法
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Tex ...