c/c++左值和右值
C/C++中的变量有左值和右值之分,他们的区别主要如下:
(1)左值可以放在赋值号 = 的左右两边,右值只能放在赋值号 = 的右边
(2)在C语言中,有名字的变量即为左值;而函数的运行结果或表达式中间变量即为右值
(3)对于内嵌类型(基本类型,即built-in types),右值是不可以被更改的,也不可以被const,volatile所修饰;
对于自定义类型,右值却可以通过它的成员函数来进行修改。
(4)左值也可以作为右值表达式,变量可以是左值,也可以为右值,但常量只能是右值。
(5)右值只能被const 类型的引用所指向;而左值可以被const或非const类型引用指向
在 c++ 中,每一个表达式都会产生一个左值,或者右值,相应的,该表达式也就被称作“左值表达式”,“右值表达式”。
例如:
++a 为将a进行自加,然后返回a,a本身就有内存地址,为一个左值,因此 (++a)++ 正确;
而 a++是后自增,在表达式里的值仍然为原来的a,返回a,然后a再被赋值为a+1。而返回的值为一个临时变量,是一个右值,不能被改变,不存在内存地址。所以(a++)++错误。
//左值只能为变量,不能是常量,因为常量不能放在赋值号左边;但右值可以是变量或常量,因为常量和变量都可以放在赋值号右边。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | #include<iostream> using namespace std; template<typename T> class ReferenceWrapper{ public : explicit ReferenceWrapper(T& t) : t_(&t){}; operator T&() const { return *t_; } T& Get() const { return *t_; } T* GetPointer() const { return t_; } void Print(){ cout << *t_ << endl; } private : T* t_; }; template<typename T> ReferenceWrapper<T> GetRW(){ static T t = 0; return ReferenceWrapper<T>(t++); } int Func(){ static int a = 0; return a++; } int main(){ int value = 10; ReferenceWrapper< int > rw(value); //构造函数 cout << rw + 100 << endl; int value1 = 100 + value; rw = ReferenceWrapper< int >(value1); //赋值号,进行构造 value = rw; //调用 T& operator() 进行隐式转换,将对象转换为 int类型 rw.Get() = value; //返回T&, 可以进行赋值操作 *rw.GetPointer() = value; //返回 T*,然后进行赋值 ( int &)rw = value; //将rw隐式转换为 T&,这时候为右值;需要进行(int&)显示转换来进行赋值操作 // rw = value; //出错, T& operator() 函数进行隐式转换,只能作为右值,不能作为左值 //函数返回一个自定义类型的变量,为右值 //但是对于自定义类型,右值可以调用类的成员函数,即 operator = ,则可以放在=左边 GetRW< int >() = ReferenceWrapper< int >(value1); //函数返回一个内嵌类型的变量,该变量为右值。不能放在=左边 Func() = 100; //右值调用类内部的成员函数 GetRW< int >().Print(); //Func 函数返回一个临时变量,为右值 //右值可以调用成员函数,只能被const 类型的引用所指向。 const int & tmp1 = Func(); int & tmp2 = Func(); //左值既可以被const也可以被非const类型的引用所指向 int a = Func(); const int & tmp3 = a; int & tmp4 = a; return 0; } |