整容说文库 > 程序代码 > 教育资讯

问两个关于const reference的问题

来源:学生作业帮助网 编辑:整容说文库 时间:2020/10/24 06:10:08 程序代码
问两个关于const reference的问题程序代码
这是我在看ruminations on c++(c++沉思录)的时候觉得不是很理解的,希望有人可以解答

这两个问题都是在第四章的最后提出来的,我把原文打下来了
1. When a function has reference parameters, should they be const references? The only time that a function should have a reference argument without saying const is when it intends to modify the argument. Thus, for example, instead of saying

Complex operator+(Complex& x, Complex& y);

you should almost certainly say,

Complex operator+(const Complex&, const Complex& y);

unless you mean to allow adding two Complex objects to change their values!(一直到这里都是很明白的)
Otherwise, expressions such as x+y+z become impossible, because x+y is not an lvalue and therefore may not have a nonconst reference bound to it.(这句话实在没有理解)

哪种情况下x+y不是lvalue?反正觉得这里写得比较混,不是很好理解。

2. Did you remember to declare your member functions const appropriately?

When a memeber function is guaranteed not to modify its object, declare it const so that it can be used for const objects. Therefore, if we use access functions as in our earlier example:

template<class T> class Vector{
public:
         int length();                            // get length(wrong)
         int length(int);                         // set length, return previous
};


the function that fetches the length without changing it should be declared const:

template<class T> class Vector{
public:
         int length() const;                      // get length(right)
         int length(int);                         // set length, return previous
};


Otherwise, we will run into trouble in contexts such as this:

/* return the larger of n and the length of v */
template<class T>
int padded_length(const Vector<T>& v, int n){
           int k = v.length();                    // oops!
           return k > n ? k:n;
}


The line flagged opps! won't compile unless the aforementioned const appears in the declaration of length, because v is a reference to const.

这段话是看明白了,就是说下面那个padded_length因为v是const的,那么这时候调用的length()函数必须也是const的,否则的话编译器就会报错

那这是不是说,凡是const objects的话,其它的非标明了const的函数就不能被执行了?

希望有人能一起讨论,谢谢了先!
该回复于2011-03-02 14:36:20被版主删除
x+y+z
可以看成是
Complex temp = y+z;
x+temp;
因为temp是一个临时变量,因此不是一个lvalue,因此不能使用被作为引用传入Complex operator+(Complex& x, Complex& y);函数
需要const 引用才能传入
我看了一下中文版的,翻译好像也没阐述更清楚,我对你的第一个疑问也是同样的。
我认为,operator+应该返回一个临时Complex对象,没什么道理不能做lvalue。

至于第二个问题,我认为你的理解是对的,这主要是编译器为了安全而提前阻止你去调用可能有问题的成员函数。尽管,你的成员函数确实是无害的---既然如此,那把成员函数加上const修饰去顺应编译器好了。

类似的,在C当中,你也会发现编译器阻止一个函数把它的const参数传递给它调用的一个不带const修饰的子函数。
引用 2 楼 thefirstz 的回复:
x+y+z
可以看成是
Complex temp = y+z;
x+temp;
因为temp是一个临时变量,因此不是一个lvalue,因此不能使用被作为引用传入Complex operator+(Complex&amp; x, Complex&amp; y);函数
需要const 引用才能传入


你的解释我看明白了,谢谢!
临时变量相当于是const型的,所以不是lvalue
而调用Complex operator(Complex& x, Complex& y)函数的时候,参数不能是const型的,否则编译器会报错(因为函数可能会改变const变量的值),所以这个函数的参数只能定义成const型的,才正确
引用 3 楼 fengzhw 的回复:
我看了一下中文版的,翻译好像也没阐述更清楚,我对你的第一个疑问也是同样的。
我认为,operator+应该返回一个临时Complex对象,没什么道理不能做lvalue。

至于第二个问题,我认为你的理解是对的,这主要是编译器为了安全而提前阻止你去调用可能有问题的成员函数。尽管,你的成员函数确实是无害的---既然如此,那把成员函数加上const修饰去顺应编译器好了。

类似的,在C当中,……


临时变量是当作const类型看待的,所以不是lvalue,这是比较关键的一点,呵呵,我现在明白了

我觉得第二个问题就是,const objects不能有函数调用改变它的状态,所以只能调用显式标明了const的函数
找了一个关于左值、右值的说明,好像临时对象做左值是不大妙:
http://hi.baidu.com/lonelinsky/blog/item/e531503c7cb2ade23d6d979b.html

而我自己对左值的理解有一些想当然的成分,主要是觉得效率上应该接受,下面这个链接讲到“右值引用”的新做法,这需要在编码时和编译器互相配合一下,而且需要很高版本的编译器。
http://www.cppblog.com/liyiwen/archive/2010/03/08/102417.html

下面是我自己临时写的一个代码,我初学,见笑了。

/*
 
考察C++沉思录第四章末尾,关于参数的const修饰问题
原文说 x + y + z 这样的运算,如果+的两个参数不是const就无法实现 
*/ 

#include <iostream>

class C {
private:
int m_v ;
public:
C(int v=0):m_v(v){ }
friend C operator+(C &c1, C &c2) ;
};

C operator+(C &c1, C &c2) 
{ int v = c1.m_v + c2.m_v; std::cout << v << std::endl; return C(v); }

int main()
{
C c1(1), c2(2);
C c3 ;
c3 = c1 + c2 ;
C c4 = c1 + c2 + c3 ;
return 0;
}

/* 
1,在gcc 3.4.4,或者gcc 4.2.3,编译时报告
constreference.cpp: In function `int main()':
constreference.cpp:25: error: no match for 'operator+' in 'operator+(((C&)(&c1))
, ((C&)(&c2))) + c3'
constreference.cpp:18: note: candidates are: C operator+(C&, C&)
 
 
 
*/
这是我找的关于lvalue和rvalue的解释,估计你看了应该就明白了

lvalue 通常指的是可以寻址并且可以对该地址内容存储的对象进行写操作 (writeable) 。可以看作 location value.
rvalue 通常指的是那些能够提供数据值的数据,即从某个 mem 中读出的 value 。可以认为是 read value.

文字常量即通常指的数字( 1 , 200 ,。。。)。该数据对象分配在常量内存区域,不可以寻址,也就是不可以通过操作它的地址值来变更的数据对象。因此不能作为 lvalue 出现,只能是 rvalue 
变量 
可以寻址,通过变量名就可以改变该数据地址的内容,所以可以成为 lvalue 、 rvalue。

总结:
lvalue :可以通过数据对象自身地址来改变数据对象值的数据对象,要求该对象可以寻址。
rvalue :能够提供数据对象本身数值的数据对象,该对象不一定可以寻址由操作符决定需要什么类型的数据值类

lvalue 中的 ’l’ 不是 left 的意思,既不是指在操作符左边。同样 ’r’ 不是 right 

例如:
x++; 
++x; 

两个表达式均要求 x 是 lvalue 。
使用举例: 
①.     0=1 ;             //error, 0 不是 lvalue 
②.     x+0.1*y=z;     //error, 在赋值运算符左边的应该为 lvalue 
③.     const int size=4; 
size=10;         //error, 数据对象地址内容不可以改变,即不是 writeable
程序代码