C++笔记整理(引用与类型转换)

十、C++的引用

1、定义

①引用即别名,就是某个变量的别名,对引用别名的操作与对变量本身完全相同。

②语法规则

类型&引用名=变量名;

int&b=a;//相当于把b引用到a上,b就是a的引用别名,b不是独立的空间。

注:引用在定义时必须初始化,初始化绑定的目标不能再改变,引用的类型要与绑定的目标类型相同

#include<iostream>
using namespace std;
int main(void){
    int a=10;
    int&b=a;//b引用a
    cout<<"a="<<a<<",b="<<b<<endl;//都为10
    cout<<"&a="<<&a<<",&b="<<&b<<endl;//地址相同
    b++;
    cout<<"a="<<a<<",b="<<b<<endl;//都为11
    int &c;//error,引用同时必须直接初始化
    int d=20;
    b=d;//ok,但是不修改引用目标的地址,仅仅是数值变了
    char&r=d;//error,引用目标与目标变量类型不一致
    return 0;
}

2、常引用

①定义引用时加上const修饰,即是常引用,不能通过常引用修改引用的目标

const 类型 &引用名=变量名

类型 const &引用名=变量名

这两个完全等价

int a=2;
const int &b=a;
b++;//error
a++;//ok

②普通引用也可以叫做左值引用,只能引用左值,常引用是万能引用,左值右值都可以引用

左值(lvalue):可以放在赋值操作符左侧,可以被修改,例如普通变量

右值(rvalue):只能放在赋值操作符右侧,不可以被修改,例如字面值常量

临时变量也是右值,例如类型转换结果的临时变量、参数表达式结果的临时变量(除前缀的++和--以及赋值)、函数中返回的临时变量

int &r1=100;//100是一个右值,不可以被引用
const int &r1=100;//常引用可以引用右值

int &r2='c';//error
int &r2=(int)'c';//error
const int &r2=(int)'c';//ok

int a=3;
int b=5;
int &r3=a+b;//error,a+b是右值
const int&r3=a+b;//ok

++a=20;//ok
--a=20;//ok
a++=20;//error
a--=20;//error
a+=10=100;//ok,a=100;a+=10是左值
int &r4=(a+=b);//ok,r4与a的地址相同


int func(void){
    int n=40;
    return n;//返回值是将亡右值
}
int main(void){
    int&r5=func();//error
    const int&r6=func();//ok,地址与n不同,是将亡右值这个临时变量的引用
    return 0;
}

3、引用传参

在C语言中函数传参,我们要改变实参时,直接传值是达不到效果的,因此必须传递实参的地址才可以,形参实参的传递过程中,伴随着实参到形参的复制过程,中间会生成临时变量,那么在C++中解决了这个问题,通过引用的方式即可直接进行值传递,提高了传参效率

#include<iostream>
using namespace std;
void swap(int *x,int *y){//C风格的两数交换
    *x=*x^*y;
    *y=*x^*y;
    *x=*x^*y;
}
void swap1(int&x,int&y){//C++风格的两数交换
    x=x^y;
    y=x^y;
    x=x^y;
}

int main(void){
    int a=5;
    int b=7;
    swap(&a,&b);//两数交换
    swap1(a,b);//也可以实现两数交换
    return 0;
}

 注:

①可以将引用于函数的参数,这时形参将是实参的别名,可以通过形参直接修改实参变量,同事还可以避免参数值传递的过程,减小函数调用开销,提高代码执行效率

②引用型参数有可能意外的修改实参,如果不希望修改实参本身,可以将参数定义为常引用,提高传参效率的同时还可以接受常量的实参

include<iostream>
using namespace std;
struct person{
    char name[100];
    int age;
    double sal;
}
void print(const Teacher&t){
    //加上const变成常引用后如果在t.age后写了++将会报错,防止意外修改实参
    //cout<<t.name<<","<<t.age++<<","<<t.sal<<endl;
    //不加常引用的话不小心写了++,每次打印age会涨一岁
    cout<<t.name<<","<<t.age<<","<<t.sal<<endl;
}
int main(void){
    person xm={"小明",20,10000};
    print(xm);
    return 0;
}

4、引用型函数返回值

例如

int&func(){

                ......

                return n;//此时返回值是左值

}

func()=100;//此时是ok的

①可将函数的返回值类型声明为引用,这时函数的返回结果就是return后面的数据的别名,可以避免函数返回至所带来的内存开销,提高代码的执行效率

②如果函数返回值是一个普通的左值引用,那么该函数调用的表达式结果也是左值

注:不要从函数中返回局部变量的引用,因为所引用的内存会在函数返回以后被释放,非常危险;

但可以返回成员变量,全局变量,静态变量的引用

#include<iostream>
using namespace std;
struct node{
    int data;
    int &func(void){
        return data;//返回成员变量ok
    }
    int &func1(void){
        int num=100;
        return num;//返回局部变量,危险!!!
    }
}
int main(void){
    node a={10};
    cout<<a.data<<endl;//100
    a.func()=200;//ok
    cout<<a.data<<endl;//200
    return 0;
}

5、引用和指针 

①从C语言的角度来看,引用的本质就是指针,但C++推荐使用引用

②指针可以不做初始化,指向也可以修改;但引用必须初始化,一旦初始化绑定目标无法修改

③可以定义指向指针的指针,不能定义引用的指针

int&r=a;
int&*pr=&r;//error

④可以定义指针的引用,但不能定义引用的引用

int a;
int *p=&a;
int *&rp=p;//ok
int &r=a;
int&&rr=r;//error

⑤可以定义指针数组,不能定义引用数组,但可以定义数组引用

int a=10,b=20,c=30;
int *parr[3]={&a,&b,&c};//ok,指针数组
int &rarr[3]={a,b,c};//error
int arr[3]={a,b,c};
int(&rarr)[3]=arr;//ok,数组引用

⑥和函数指针类似,也可以定义函数引用,相当于函数的别名,语法特性与函数保持一致

void func(int a,intb){}
int main(void){
    void(*p_func)(int,int)=func;//ok,函数指针
    void(&r_func)(int,int)=func;//ok,函数引用

十一、类型转换

1、隐式类型转换

char c='a';

int i=c;//隐式转换

编译器自己进行的转行,代码可读性差,易出错

2、显示类型转换

①C++兼容C语言的强制转换

int i=(int)c;//C风格的强制转换

int i=int(c);//C++风格的强制转换

②C++增加了四种操作符形式的类型转换

1)静态类型转换:static_cast

最常用的类型转换,在正常情况下的类型转换

如把int转换成float

int i;

float f;

f=static_cast<float>(i);

完成基础数据类型char 、int、 float、 double..,编译器会提供静态类型检测,确定是否可以进行类型转换,不能完成*类型的转换,对于丢失精度,拓展精度等情况,会编译报错

同一个继承体系中类型的转换

父类转子类(不安全):子类包含内容更多、所占内存更大。

子类转父类(安全):子类包含着父类,不会超过父类的界限。

虽然无法完成*类型转换,但任意类型与空指针类型void*之间的转换是可以的,可以通过void*间接转换

2)动态类型转换:dynamic_cast

该类型用于运行时检查转换类型是否安全,但只用在多态,并且该类至少具有一个虚拟方法,语法与上述相同,只要用于类层次间的上行和下行转换,类之间的交叉转换,但比static_cast更安全,后续到类的实现时进行使用说明

3)去常类型转换:const_cast

用于取出const属性,把const类型指针变为非const类型的指针,一般是在我们定义了只读变量后又想要更改它,可以起到临时更改的作用

const int *fun(int a,int b){}

int*ptr=const_cast<int*>(fun(2,3));//没有去常的话无法将一个const int*给一个int*,相当于放                                                              //大权限会报错

4)重解释类型转换:reinterpret_cast

int i;

char*ptr="hello";

i=reinterpret_cast<int>(ptr);

就是强行转换,这种一般很少用,除非程序员对要强转的结果非常自信,才会使用强行转换

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++中,string与wstring类型转换一般有以下几种方法: 方法一:使用标准库std::wstring_convert和std::codecvt_utf8_utf16(或std::codecvt_utf8<wchar_t>)进行转换。这个方法在C++11和C++14标准下是可用的,但在C++17标准下已经被弃用。示例代码如下: ```cpp #include <string> #include <locale> #include <codecvt> // convert string to wstring std::wstring to_wide_string(const std::string& input) { std::wstring_convert<std::codecvt_utf8<wchar_t>> converter; return converter.from_bytes(input); } // convert wstring to string std::string to_byte_string(const std::wstring& input) { std::wstring_convert<std::codecvt_utf8<wchar_t>> converter; return converter.to_bytes(input); } ``` 这种方法适用于C++11和C++14标准,但不适用于C++17标准。 方法二:使用内联函数和std::wstring_convert进行转换。这个方法也使用了std::codecvt_utf8<wchar_t>进行编码转换。示例代码如下: ```cpp #include <string> #include <locale> #include <codecvt> // convert string to wstring inline std::wstring to_wide_string(const std::string& input) { std::wstring_convert<std::codecvt_utf8<wchar_t>> converter; return converter.from_bytes(input); } // convert wstring to string inline std::string to_byte_string(const std::wstring& input) { std::wstring_convert<std::codecvt_utf8<wchar_t>> converter; return converter.to_bytes(input); } ``` 这种方法与方法一类似,只是使用了内联函数来进行转换。 方法三:使用Windows系统特有的宽字符串定义L"wstring"来进行转换。这个方法适用于Windows系统,在C开发中经常用到。示例代码如下: ```cpp #include <string> #include <windows.h> // convert string to wstring std::wstring to_wide_string(const std::string& input) { int size = MultiByteToWideChar(CP_UTF8, 0, input.c_str(), -1, nullptr, 0); std::wstring output(size, L'\0'); MultiByteToWideChar(CP_UTF8, 0, input.c_str(), -1, &output<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [C++string与wstring类型转换](https://blog.csdn.net/qq_30386941/article/details/126814596)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [C++11:string和wstring之间互转换](https://blog.csdn.net/qq_43331089/article/details/123438581)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值