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++的差别的,但的确他们直接是 ...
随机推荐
- python3.10.0字符串基础
字符串支持 索引 (下标访问),第一个字符的索引是 0.单字符没有专用的类型,就是长度为一的字符串: >>> word = 'Python' >>> word[0] ...
- Antlr语法优化过程记录
背景 Modelica Spec中的语法文件在Antlr下表现很糟糕,至少是1个数量级的糟糕的性能表现 理论 语义谓词减慢速度 ATN图中多分支转换为单分支 可选放在词法开头和语法的结尾 避免前导可选 ...
- startActivity 新开一个Activity
private void startActivity(Intent intent) { Context ctx = ApplicationController.getTopActivity(); if ...
- (K8s学习笔记七)Pod的升级和回滚
1.Deployment的升级 示例:滚动升级busybox-deployment容器 apiVersion: apps/v1 kind: Deployment metadata: name: bus ...
- babel npm包说明
babel-plugin-import 用于按需加载,在使用antd 的时候引入,可以减少包体积
- gitea 常用命令
gitea 常用命令 配置文件位置 /home/custom/conf/app.ini cd //home启动nohup ./gitea web & [root@iZ4jbz0xj0nx7 ...
- continue练习
using System; namespace continue_的练习 { class Program { static void Main(string[] args) { int sum = 0 ...
- 暑假学习二 8.24 Hadoop的环境配置
今日学习内容: 主要为Hadoop的环境配置,相关配置所需文档可以留言(?)会给发送 1.hadoop介绍: 狭义: 核心组件,Hadoop hdfs 分布存储 yarn 资源管理和任务调度框架 ...
- linux篇之WC(word count)的使用概述
Text. Linux系统中的wc(Word Count)命令的功能为统计指定文件中的字节数.字数.行数,并将统计结果显示输出. 1.命令格式: wc [选项] [文件1] [文件2] ... 2.命 ...
- 上传文件-jq
var formFile = new FormData(); formFile.append("[file]", fileObj); formFile.append("t ...