随笔 - 30, 文章 - 0, 评论 - 64, 引用 - 0
数据加载中……

正确的方法是定义operator++以reference为参数类型 C++中Reference与指针(Pointer)的使用对比

day &operator++(day &d)
{
d = (day)(d + 1);
return d;
}

使用这个函数, 表达式 ++x 才有正确的显示以及正确的操作。
Passing by reference不仅仅是写operator++较好的方法,而是唯一的方法。


 C++在这里并没有给我们选择的余地。
 像下面的声明:
day *operator++(day *d);
是不能 通过编译的。
每个重载的操作符函数必须或者是一个类的成员, 或者使用类型T、 T & 或 T const & 为参数类型,
这里T是一个类(class)或列举(enumeration)类型。

也就是说,每一个重载操作符必须以类或列举类型为参数类型。

指针,即使是指向一个类或列举类型对象的指针,也不可以用。

C++ 不允许在重载操作符时重新定义内置操作符的含义,包括指针类型。
因此,我们不可以定义:
int operator++(int i); // 错误
因为它试图对int重新定义操作符 ++ 的含义。 我们也不可以定义:
int *operator++(int *i); // 错误
因为它试图对 int * 重新定义操作符 ++ 的含义

 

 

References vs. const pointers

C++ 中不允许定义”const reference”,
 因为一个reference天生就是const。也就是说,一旦将一个reference绑定到一个对象,就无法再将它重新绑定到另一个不同的对象。
在声 明一个reference之后没有写法可以将它重新绑定到另外一个对象。
例如:
int &ri = i;
将 ri 绑定到 i 。然后下面的赋值:
ri = j;
并不是把 ri 绑定到 j ,而是将 j 中的值赋给 ri 指向的对象,也就是赋给 i 。



简而言之,
一个pointer在它的有生之年可以指向许多不同的对象,
而一个reference只能够指向一个对象。
有些人认为这才是 reference和 pointer最大的不同。
我并不赞成。也许这是reference与pointer的一点不同, 但并不是reference和const pointer的不同。
在强调一遍,一旦一个reference与一个对象绑定,就不能再将它改指向另外的东西。
既然不能再绑定reference之后再 改变, 一个reference就必须在一出生就被绑定。
否则这个reference就永远不能被绑定到任何东西,也就毫无用处了。

上一段的讨论也同样完全适用于常量指针(const pointer)。
(注意,我这里说的是常量指针(const pointer), 而不是指向常量的指针 “pointers to const”。)
 例如,
一个reference声明必须同时带有一个初始化赋值,如下所示:

void f()
{
int &r = i;

}

省略这个初始化赋值将产生一个编译错误:

void f()
{
int &r; //错误

}

一个常量指针的声明也同样必须带有一个初始化赋值,如下所示:

void f()
{
int *const p = &i;

}

省略这个初始化赋值同样会出错:

void f(){
int *const p; // 错误

}

在我看来
不能够对reference二次绑定作为reference与pointer的不同。
并不比常量指针和非常量指针的不同更为显著。




Null references

除了显示的不同,常量指针与reference还有一点非常不同,那就是,一个有效的reference必须指向一个对象;而一个指针不需要。一个指针,即使是一个常量指针, 都可以有空值。 一个空指针不指向任何东西。

这点不同就暗示当你想要确信一个参数必须指向一个对象的时候,应该使用reference作为参数类型。 例如,交换函数(swap function),它接受两个int参数,并将两个参数的数值对调,如下所示:

int i, j;
swap(i, j);

将原本在 i 中的值放到 j 中, 并将原本在 j 中的值放到 i 中。我们可以这样写这个函数:

void swap(int *v1, int *v2)
{
int temp = *v1;
*v1 = *v2;
*v2 = temp;
}

这种定义下,函数要像这样被调用: swap(&i, &j);

这个接口暗示其中一个或两个参数都有可能为空(null)。而这个暗示是误导的。例如,调用
swap(&i, NULL);
的后果很可能是不愉快的。

而像下面这样定义reference为参数:

void swap(int &v1, int &v2)
{
int temp = v1;
v1 = v2;
v2 = temp;
}

清晰的表明了调用swap应该提供两个对象,它们的值将被交换。 并且这样定义的另一个好处是,在调用这个函数的时候,不需要使用那些&符号,看起来更顺眼:
swap(i, j);








 

Null references

除了显示的不同,
常量指针与reference还有一点非常不同,
那就是,一个有效的reference必须指向一个对象;

一个指针不需要
一个指针,即使是一个常量指针, 都可以有空值。 一个空指针不指向任何东西。

这点不同就暗示当你想要确信一个参数必须指向一个对象的时候,应该使用reference作为参数类型。
 例如,
交换函数(swap function),它接受两个int参数,并将两个参数的数值对调,如下所示:

int i, j;
swap(i, j);

将原本在 i 中的值放到 j 中, 并将原本在 j 中的值放到 i 中。我们可以这样写这个函数:

void swap(int *v1, int *v2)
{
int temp = *v1;
*v1 = *v2;
*v2 = temp;
}

这种定义下,函数要像这样被调用: swap(&i, &j);

这个接口暗示其中一个或两个参数都有可能为空(null)。而这个暗示是误导的。例如,调用
swap(&i, NULL);
的后果很可能是不愉快的。

而像下面这样定义reference为参数:

void swap(int &v1, int &v2)
{
int temp = v1;
v1 = v2;
v2 = temp;
}

清晰的表明了调用swap应该提供两个对象,它们的值将被交换。 并且这样定义的另一个好处是,在调用这个函数的时候,不需要使用那些&符号,看起来更顺眼:
swap(i, j);


更安全?


有些人认为既然reference不能够为空,那么它应该比指针更安全。
 我认为reference可能要安全一点,但不会安全很多。
虽然一个有效的reference不能为空,但是无效的可以呀。
实际上,在很多情况下程序有可 能产生无效的reference,而不只是空的reference。

 例如,
你可以定义一个reference,使它绑定到一个指针指向的对象,如下所示:

int *p;

int &r = *p;

如果指针*p在reference定义时刚好为空,则这个reference为空。
 从技术上来说,这个错误并不在于将reference绑定到一个空值,而是在于对一个空指针去参考。
 对一个空指针去参考产生了一个不确定的操作,也就意味着很多事都可能发生,而且大部分都不是什么好事。很有可能当程序将reference r 绑定到*p (p所指向的对象)的时候,p实际上没有被去参考,甚至程序只是将p的值拷贝给实现r的指针。
而程序将会继续执行下去直到错误在后面的运行中更为明显的表 现出来,产生不可预知的危害。

下面的函数
展示了
另外一种产生无效reference的方法:

int &f()
{
int i;

return i;
}

这个函数返回一个指向本地变量 i 的reference。
然而当函数返回时,本地变量 i 的存储空间也就消失了。因此这个函数实际返回了一个指向被回收了的空间的reference。这个操作与返回一个指向本地变量的指针的后果相同。
有些编译 器可以在编译时发现这个错误,但也很有可能不会发现。




我喜欢reference,也有很好的理由使用它们代替pointer。

但如果你期望使用reference来使你的程序健壮性显著增强,那么你多半会失望的



参考资料:

  1. Saks, Dan. “Introduction to References,” Embedded Systems Programming, January 2001, p. 81.
  2. Saks, Dan. “References and const“, Embedded Systems Programming February 2001, p. 73.

posted on 2008-12-09 13:16 henry08 阅读(2130) 评论(2)  编辑 收藏 引用 所属分类: C++

评论

# re: 正确的方法是定义operator++以reference为参数类型 C++中Reference与指针(Pointer)的使用对比  回复  更多评论   

day& operator++(day& d)
{
d = (day)(d + 1);
return d;
}

在我不准确的记忆中,似乎这段代码不符合后缀式++运算符的语义吧?

我以为应该这样:
day operator++(day& d)
{
day tmp = d;
d += 1;
return tmp;
}
2008-12-09 20:01 | buxoman

# re: 正确的方法是定义operator++以reference为参数类型 C++中Reference与指针(Pointer)的使用对比  回复  更多评论   

我喜欢reference,也有很好的理由使用它们代替pointer

============================================
如果你的目的是代替的话,你会发现有很多地方是不愉快的
2008-12-10 09:52 | zuhd

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理