IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++ &以及&&的用法总结 -> 正文阅读

[C++知识库]C++ &以及&&的用法总结

首先,&有两种用法:

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 只对构造函数起作用,用来抑制隐式转换

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-09 10:03:37  更:2021-08-09 10:06:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/9 15:18:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码