&以及&&的用法总结
&有两种用法
1、取地址
2、引用
取地址和引用没有任何关系,不要瞎联系!
1、取地址:
// 很常规,仅此而已
std::string *p = &s;
2、引用:
a)引用是某一个变量或者对象的别名,对引用的操作与对其所绑定的变量或对象的操作完全等价。而引用中使用 & ,跟地址没有任何关系,仅仅是起到标志作用。
int a = 10; // 引用的类型必须和其所绑定的变量的类型相同;且必须初始化。
int &b = a;
b)引用相当于变量或者对象的别名,不能将已有的引用名作为其他变量或者对象的引用名,引用名具有唯一性,绑定后不可再作为其他变量名或者新的变量对象的引用别名,即不可再作为新的声明使用。
c) 引用不是定义一个新的变量,不会为引用开辟新的内存空间。
d)对数组的引用需要加上数组的大小
int a[3] = {1, 2, 3};
int (&b) [3] = a;
e)对指针的引用
int a = 1;
int *p = &a; // 指针引用
int * &pp = p;
f)引用作为函数的参数
#include<iostream>
using namespace std; void swap(int &a,int &b){
int temp=a;
a=b;
b=temp;
}
int main(){ int value1=10,value2=20; cout<<"----------------------交换前----------------------------"<<endl;
cout<<"value1的值为:"<<value1<<endl;
cout<<"value2的值为:"<<value2<<endl; swap(value1,value2); cout<<"----------------------交换后----------------------------"<<endl;
cout<<"value1的值为:"<<value1<<endl;
cout<<"value2的值为:"<<value2<<endl; return 0;
}
引用作为函数参数使用注意,需要指出的是:
I)当引用作为参数的时候,其效果跟利用指针作为参数的效果相当。当调用函数时,函数中的形参就会被当成实参变量或者对象的一个别名使用,也就是说函数中对形参的各种操作实际上就是对实参本身的操作,而非简单的实参变量或者对象的值拷贝给形参。
II) ①值传递方式传参: 通常函数调用时采用值传递的方式,系统会在内存中开辟空间用来存储形参变量,并将实参变量的值拷贝给形参变量,所以形参变量只是实参变量的副本而已,并且如果函数传递的是类的对象,系统还会调用类中的拷贝构造函数来构造形参对象。
② 引用方式传参:而使用引用作为参数传递时,由于此时形参只是传递函数的实参变量或者对象的别名而非副本,故系统不会耗费时间在内存中开辟空间来存储形参,因此如果参数传递的数据较大,建议使用引用作为函数的形参,提高函数的时间效率,节省内存空间。
③ 指针方式传参:使用指针作为函数的形参,虽然达到的效果跟使用引用一样,但当调用函数时仍然需要为形参指针分配空间,引用则不需要【引用在底层也会分配指针大小的空间,在汇编底层角度,引用和指针是一样的,不过引用类似于常量指针】。推荐使用引用而非指针作为函数的传递函数。
④ *常量引用保护传递:如果既希望通过引用作为函数形参提高效率,又希望保护传递的参数在函数中不被改变,则可以使用对常量的引用作为函数的形参。
另外,如果使用数组的引用作为函数形参,引用传递时指明的是数组则必须指定数组的长度
#include<iostream>
using namespace std; void func(int(&a)[5]){
// !-! 数组引用作为函数的参数,必须指明数组的长度 // do something ...
} int main(){
int number[5]={0,1,2,3,4};
func(number);
return 0;
}
g)常引用
常引用,不允许通过该引用对其所绑定的变量或者对象进行修改。值得注意的是,C++ 中所有的临时变量都是 const 类型的。
#include<iostream>
#include<string>
using namespace std; string func1(){
string temp="This is func1";
return temp;
}
void func2(const string &str){
cout<<str<<endl;
} int main(){
// 在 main 中会将 func1() 返回的对象 temp 首先赋予一个临时对象,
// 之后再对该临时变量操作,如赋值给新的变量等。
string returned_temp = func1(); // 所以将 func1() 产生的临时对象值传递给 func2() 时,
// 必须要注意的是: 要使用 const 的形参 void func2(const string &str)...
// 否则会出现“试图将 const 对象赋值给非 cosnt 对象的错误”。
func2(func1()); // “Tomwenxing” 类似。
func2("Tomwenxing");
return 0;
}
h)引用作为函数的返回值
引用作为函数返回值时,必须在定义函数时在函数名前加 &;使用引用作为函数的返回值的最大的好处是在内存中不产生返回值的副本。
#include<iostream>
using namespace std; float temp; float fn1(float r){
temp = r*r*3.14;
return temp;
} float &fn2(float r){
// & 说明返回的是 temp 的引用,也就是返回 temp 本身
temp = r*r*3.14;
return temp;
} int main(){ // case 1:返回值 -----------------------------------------------------------------
// 在内存中创建临时变量,并将 temp 的值拷贝给该临时变量。
// 当返回到主函数 main 后,赋值语句 a = fn1(5.0)
// 会把临时变量的值再拷贝给变量 a。
float a = fn1(5.0); // case 2: 用函数的返回值作为引用的初始化值 ---------------------------------------
// float &b = fn1(5.0);
// [Error] invalid initialization of non-const reference of type 'float&' from an
// rvalue of type 'float'
// 逻辑是首先拷贝 temp 的值给临时变量。返回到主函数后,用临时变量来初始化引用变量 b
// 使得b成为该临时变量到的别名。但是临时变量的作用域短暂(仅仅是一句表达式)会使得 b
// 有无效的风险。所以建议使用
float x = fn1(5.0);
float &b = x; // case 3:返回引用 --------------------------------------------------------------
// 函数 fn2() 的返回值不产生副本,而是直接将变量 temp 返回给主函数,即主函数的赋值语
// 句中的左值是直接从变量 temp 中拷贝而来(也就是说 c 只是变量 temp 的一个拷贝而非别
// 名, 拷贝是从赋值语句来的)
float c = fn2(5.0); // case 4:用函数返回的引用作为新引用的初始化值 ----------------------------------
// 函数 fn2() 的返回值不产生副本,而是直接将变量 temp 返回给主函数。在主函数中,一个
// 引用声明 d 用该返回值初始化,也就是说此时 d 成为变量 temp 的别名。由于 temp 是全
// 局变量,所以在 d 的有效期内 temp 始终保持有效,故这种做法是安全的。
float &d = fn2(5.0); // 不能返回局部变量的引用。如上面的例子,如果 temp 是局部变量,那么它会在函数返回后
// 被销毁,此时对 temp 的引用就会成为“无所指”的引用,程序会进入未知状态。 // 不能返回函数内部通过 new 分配的内存的引用。虽然不存在局部变量的被动销毁问题,但如
// 果被返回的函数的引用只是作为一个临时变量出现,而没有将其赋值给一个实际的变量,那么
// 就可能造成这个引用所指向的空间(有 new 分配)无法释放的情况(由于没有具体的变量名,
// 故无法用 delete 手动释放该内存),从而造成内存泄漏。 // 当返回类成员的引用时,最好是 const 引用。这样可以避免在无意的情况下破坏该类的成员。 cout<<a<<endl; //78.5
//cout<<b<<endl; //78.5
cout<<c<<endl; //78.5
cout<<d<<endl; //78.5 return 0;
}
i)在C++中,引用是除了指针外另一个可以产生多态效果的手段。也就是说一个基类的引用可以用来绑定其派生类的实例。ptr只能用来访问派生类对象中从基类继承下来的成员。如果基类(类Father)中定义的有虚函数,那么就可以通过在派生类(类Son)中重写这个虚函数来实现类的多态。
class Father; //基类(父类)
class Son:public Father{.....} //Son是Father的派生类
Son son; //son是类Son的一个实例
Father &ptr=son; //用派生类的对象初始化基类对象的使用
&总结:
在引用的使用中,单纯给某个变量去别名是毫无意义的,引用的目的主要用于在函数参数的传递中,解决大块数据或对象的传递效率和空间不如意的问题
用引用传递函数的参数,能保证参数在传递的过程中不产生副本,从而提高传递效率,同时通过const的使用,还可以保证参数在传递过程中的安全性
引用本身是目标变量或对象的别名,对引用的操作本质上就是对目标变量或对象的操作。因此能使用引用时尽量使用引用而非指针。
&& 是右值引用
左值和右值
左值的英文简写为“lvalue”,右值的英文简写为“rvalue”。很多人认为它们分别是"left value"、"right value" 的缩写,其实不然。lvalue 是“loactor value”的缩写,可意为存储在内存中、有明确存储地址(可寻址)的数据,而 rvalue 译为 "read value",指的是那些可以提供数据值的数据(不一定可以寻址,例如存储于寄存器中的数据)。
// 左值引用
int num = 10;
int &b = num; // 正确
int &c = 10; // 错误 int num = 10;
const int &b = num; // 正确
const int &c = 10; // 正确 // 右值引用
int num = 10;
//int && a = num; // 错误,右值引用不能初始化为左值
int && a = 10; // 正确 a = 100;
cout << a << endl; // 输出为100,右值引用可以修改值 // 右值引用的使用
// 如 thread argv 的传入
template<typename _Callable, typename... _Args>
explicit thread(_Callable&& __f, _Args&&... __args) {
//....
}
// Args&&... args 是对函数参数的类型 Args&& 进行展开
// args... 是对函数参数 args 进行展开
// explicit 只对构造函数起作用,用来抑制隐式转换
————————————————
版权声明:本文为CSDN博主「伯叔而已」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Z_xOOOO/article/details/119515300
&以及&&的用法总结的更多相关文章
- EditText 基本用法
title: EditText 基本用法 tags: EditText,编辑框,输入框 --- EditText介绍: EditText 在开发中也是经常用到的控件,也是一个比较必要的组件,可以说它是 ...
- jquery插件的用法之cookie 插件
一.使用cookie 插件 插件官方网站下载地址:http://plugins.jquery.com/cookie/ cookie 插件的用法比较简单,直接粘贴下面代码示例: //生成一个cookie ...
- Java中的Socket的用法
Java中的Socket的用法 Java中的Socket分为普通的Socket和NioSocket. 普通Socket的用法 Java中的 ...
- [转载]C#中MessageBox.Show用法以及VB.NET中MsgBox用法
一.C#中MessageBox.Show用法 MessageBox.Show (String) 显示具有指定文本的消息框. 由 .NET Compact Framework 支持. MessageBo ...
- python enumerate 用法
A new built-in function, enumerate() , will make certain loops a bit clearer. enumerate(thing) , whe ...
- [转载]Jquery中$.get(),$.post(),$.ajax(),$.getJSON()的用法总结
本文对Jquery中$.get(),$.post(),$.ajax(),$.getJSON()的用法进行了详细的总结,需要的朋友可以参考下,希望对大家有所帮助. 详细解读Jquery各Ajax函数: ...
- 【JavaScript】innerHTML、innerText和outerHTML的用法区别
用法: <div id="test"> <span style="color:red">test1</span> tes ...
- chattr用法
[root@localhost tmp]# umask 0022 一.chattr用法 1.创建空文件attrtest,然后删除,提示无法删除,因为有隐藏文件 [root@localhost tmp] ...
- 萌新笔记——vim命令“=”、“d”、“y”的用法(结合光标移动命令,一些场合会非常方便)
vim有许多命令,网上搜有一堆贴子.文章列举出各种功能的命令. 对于"="."d"."y",我在无意中发现了它们所具有的相同的一些用法,先举 ...
- [转]thinkphp 模板显示display和assign的用法
thinkphp 模板显示display和assign的用法 $this->assign('name',$value); //在 Action 类里面使用 assign 方法对模板变量赋值,无论 ...
随机推荐
- Ubuntu18.04修改IP地址的方法
转载csdn: ubuntu18.04更改本地IP_lvjianjin128的博客-CSDN博客 Ubuntu18.04修改IP地址的方法_VLadimir_的博客-CSDN博客_ubuntu18.0 ...
- JavaSE 对象与类(二)
6.对象构造 重载:如果有多个方法(比如,StringBuilder构造器方法)有相同的名字.不同的参数.便产生了重载. 重载解析:编译器通过用各个方法给出的参数类型与特定方法调用所使用的值类型进行匹 ...
- 网页js版音频数字信号处理:H5录音+特定频率信号的特征分析和识别提取
目录 一.网页中的音频数据源 二.FFT:时域转频域 三.信号的特征分析 四.信号的识别提取 附录 音频数字信号处理 Audio DSP (Digital Signal Processing) 是一个 ...
- PostGIS之空间索引
1. 概述 PostGIS 是PostgreSQL数据库一个空间数据库扩展,它添加了对地理对象的支持,允许在 SQL 中运行空间查询 PostGIS官网:About PostGIS | PostGIS ...
- 添加material ui库
ng add @angular/material 自定义预构建主题 ? Choose a prebuilt theme name, or "custom" for a custom ...
- [引擎开发] 深入GPU和渲染优化(基础篇)
https://blog.csdn.net/ZJU_fish1996/article/details/109269448
- MySQL 8.0 新特性-原子DDL
背景 MySQL 8.0 原子DDL 是一个复杂的过程,涉及比较多的模块,例如:MDL 锁,表定义缓存,行格式,Row Log,DDL Log,online 属性,表空间物理文件操作等.本文主要通过与 ...
- Centos7 安装mysql 5.7 教程
安装 yum 源 需要在系统上启用 MySQL 5.7 Community Release YUM 存储库.用于 yum 存储库配置的 rpm 包可在 MySQL 的官方网站上找到. 首先将最新的My ...
- 06 RDD编程
总共有多少学生?map(), distinct(), count() 开设了多少门课程? 每个学生选修了多少门课?map(), countByKey() 每门课程有多少个学生选?map(), coun ...
- containerd 卸载
一.创建脚本 cat > remove.sh <<EOF #!/bin/bash # 删除contained命令及配置 rm -rf /usr/local/bin/ rm -rf / ...