C++的引用和指针还有句柄的东西

简介: 使用句柄的另一个时机是想要将已经完成的东西含糊化的时候(有时用术语magic cookie也一样,就像这样,“软件传递一个magic cookie来唯一标识并定位适当的Fred对象”)。
什么是引用?
对象的别名(另一个名称)。

引用经常用于“按引用传递(pass-by-reference)”:


 void swap(int& i, int& j)
 {
   int tmp = i;
   i = j;
   j = tmp;
 }
 
 int main()
 {
   int x, y;
   // ...
   swap(x,y);
 } 
此处的 i 和 j 分别是main中的 x 和 y。换句话说,i 就是 x —— 并非指向 x 的指针,也不是 x 的拷贝,而是 x 本身。对 i 的任何改变同样会影响 x,反之亦然。

OK,这就是作为一个程序员所认知的引用。现在,给你一个不同的角度,这可能会让你更糊涂,那就是引用是如何实现的。典型的情况下,对象 x 的引用 i 是 x 的机器地址。但是,当程序员写 i++ 时,编译器产生增加 x 的代码。更详细的来说,编译器用来寻找 x 的地址位并没有被改变。C 程序员将此认为好像是 C 风格的按指针传递,只是句法不同 (1) 将 & 从调用者移到了被调用者处,(2)消除了*s。换句话说,C 程序员会将 i 看作为宏 (*p),而 p 就是指向 x 的指针(例如,编译器自动地将潜在的指针解除引用;i++被改变为 (*p)++;i = 7 被自动地转变成 *p = 7)。

很重要:请不要将引用看作为指向一个对象的奇异指针,即使引用经常是用汇编语言下的地址来实现的。引用就是对象。不是指向对象的指针,也不是对象的拷贝,就是对象。 

--------------------------------------------------------------------------------


给引用赋值,意味着什么? 
改变引用的“指示物”(引用所指的对象)。

请记住: 引用就是它的指示物,所以当改变引用的值时,也会改变其指示物的值。以编译器编写者的行话来说,引用是一个“左值”(它可以出现在赋值运算符左边)。


--------------------------------------------------------------------------------


 返回一个引用,意味着什么? 
意味着该函数调用可以出现在赋值运算符的左边。

最初这种能力看起来有些古怪。例如,没有人会认为表达式 f() = 7 有意义。然而,如果 a 是一个 Array 类,大多数人会认为 a = 7 有意义,即使 a 实际上是一个函数调用的伪装(它调用了 如下的 Array 类的 Array::operator[](int))。


 class Array {
 public:
   int size() const;
   float& operator[] (int index);
   // ...
 };
 
 int main()
 {
   Array a;
   for (int i = 0; i < a.size(); ++i)
     a = 7;    // 这行调用了 Array::operator[](int)
 } 


--------------------------------------------------------------------------------


object.method1().method2() 是什么意思? 

连接这些方法的调用,因此被称为方法链

第一个被执行的是 object.method1()。它返回对象,可能是对象的引用(如,method1()可能以 return *this 结束),或可能是一些其他对象。我们姑且把返回的对象称为objectB。然后objectB成为method2()的this对象。

方法链最常用的地方是iostream库。例如,cout << x << y 可以执行因为 cout << x是一个返回cout.的函数

虽然使用的较少,但仍然要熟练掌握的是在命名参数法(Named Parameter Idiom)中使用方法链。


--------------------------------------------------------------------------------


 如何能够使一个引用重新指向另一个对象? 
不行。

你无法让引用与其指示物分离。

和指针不同,一旦引用和对象绑定,它无法再被重新指向其他对象。引用本身不是一个对象(它没有标识; 当试图获得引用的地址时,你将的到它的指示物的地址;记住:引用就是它的指示物)。

从某种意义上来说,引用类似 int* const p  这样的const指针(并非如 const int* p 这样的指向常量的指针)。不管有多么类似,请不要混淆引用和指针;它们完全不同。


--------------------------------------------------------------------------------


何时该使用引用, 何时该使用指针?
尽可能使用引用,不得已时使用指针。

当你不需要“重新指向(reseating)”时,引用一般优先于指针被选用。这通常意味着引用用于类的公有接口时更有用。引用出现的典型场合是对象的表面,而指针用于对象内部。

上述的例外情况是函数的参数或返回值需要一个“临界”的引用时。这时通常最好返回/获取一个指针,并使用 NULL 指针来完成这个特殊的使命。(引用应该总是对象的别名,而不是被解除引用的 NULL 指针)。

注意:由于在调用者的代码处,无法提供清晰的的引用语义,所以传统的 C 程序员有时并不喜欢引用。然而,当有了一些 C++ 经验后,你会很快认识到这是信息隐藏的一种形式,它是有益的而不是有害的。就如同,程序员应该针对要解决的问题写代码,而不是机器本身。

--------------------------------------------------------------------------------


什么是对象的句柄?它是指针吗?它是引用吗?它是指向指针的指针?它是什么? 
[Recently created (on 4/01). Click here to go to the next FAQ in the "chain" of recent changes.] 
句柄术语一般用来指获取另一个对象的方法——一个广义的假指针。这个术语是(故意的)含糊不清的。

含糊不清在实际中的某些情况下是有用的。例如,在早期设计时,你可能不准备用句柄来表示。你可能不确定是否将一个简单的指针或者引用或者指向指针的指针或者指向引用的指针或者整型标识符放在一个数组或者字符串(或其它键)以便能够以哈希表(hash-table)(或其他数据结构)或数据库键或者一些其它的技巧来查询。如果你只知道你会需要一些唯一标识的东西来获取对象,那么这些东西就被称为句柄。

因此,如果你的最终目标是要让代码唯一的标识/查询一个Fred类的指定的对象的话,你需要传递一个Fred句柄这些代码。句柄可以是一个能被作为众所周知的查询表中的键(key)来使用的字符串(比如,在std::map<std::string,Fred> 或 std::map<std::string,Fred*>中的键),或者它可以是一个作为数组中的索引的整数(比如,Fred* array = new Fred[maxNumFreds]),或者它可以是一个简单的 Fred*,或者它可以是其它的一些东西。


初学者常常考虑指针,但实际上使用未初始化的指针有底层的风险。例如,如果Fred对象需要移动怎么办?当Fred对象可以被安全删除时我们如何获知?如果Fred对象需要(临时的)连续的从磁盘获得怎么办?等等。这些时候的大多数,我们增加一个间接层来管理位置。例如,句柄可以是Fred**,指向Fred*的指针可以保证不会被移动。当Fred对象需要移动时,你只要更新指向Fred*的指针就可以了。或者让用一个整数作为句柄,然后在表或数组或其他地方查询Fred的对象(或者指向Fred对象的指针)。


重点是当我们不知道要做的事情的细节时,使用句柄。

使用句柄的另一个时机是想要将已经完成的东西含糊化的时候(有时用术语magic cookie也一样,就像这样,“软件传递一个magic cookie来唯一标识并定位适当的Fred对象”)。将已经完成的东西含糊化的原因是使得句柄的特殊细节或表示物改变时所产生的连锁反应最小化。举例来说,当将一个句柄从用来在表中查询的字符串变为在数组中查询的整数时,我们可不想更新大量的代码。

当句柄的细节或表示物改变时,维护工作更为简单(或者说阅读和书写代码更容易),因此常常将句柄封装到类中。这样的类常重载operator-> 和 operator*算符(既然句柄的效果象指针,那么它可能看起来也象指针)。

目录
相关文章
|
14天前
|
存储 安全 编译器
在 C++中,引用和指针的区别
在C++中,引用和指针都是用于间接访问对象的工具,但它们有显著区别。引用是对象的别名,必须在定义时初始化且不可重新绑定;指针是一个变量,可以指向不同对象,也可为空。引用更安全,指针更灵活。
|
1月前
|
存储 C++
c++的指针完整教程
本文提供了一个全面的C++指针教程,包括指针的声明与初始化、访问指针指向的值、指针运算、指针与函数的关系、动态内存分配,以及不同类型指针(如一级指针、二级指针、整型指针、字符指针、数组指针、函数指针、成员指针、void指针)的介绍,还提到了不同位数机器上指针大小的差异。
28 1
|
1月前
|
存储 编译器 C语言
C++入门2——类与对象1(类的定义和this指针)
C++入门2——类与对象1(类的定义和this指针)
23 2
|
1月前
|
存储 安全 编译器
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(一)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
|
1月前
|
存储 C++ 索引
C++函数指针详解
【10月更文挑战第3天】本文介绍了C++中的函数指针概念、定义与应用。函数指针是一种指向函数的特殊指针,其类型取决于函数的返回值与参数类型。定义函数指针需指定返回类型和参数列表,如 `int (*funcPtr)(int, int);`。通过赋值函数名给指针,即可调用该函数,支持两种调用格式:`(*funcPtr)(参数)` 和 `funcPtr(参数)`。函数指针还可作为参数传递给其他函数,增强程序灵活性。此外,也可创建函数指针数组,存储多个函数指针。
|
2月前
|
编译器 C++
【C++核心】指针和引用案例详解
这篇文章详细讲解了C++中指针和引用的概念、使用场景和操作技巧,包括指针的定义、指针与数组、指针与函数的关系,以及引用的基本使用、注意事项和作为函数参数和返回值的用法。
35 3
|
1月前
|
算法 C++
【算法】双指针+二分(C/C++
【算法】双指针+二分(C/C++
|
1月前
|
存储 编译器 程序员
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(二)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
|
2月前
|
C++
C++(十八)Smart Pointer 智能指针简介
智能指针是C++中用于管理动态分配内存的一种机制,通过自动释放不再使用的内存来防止内存泄漏。`auto_ptr`是早期的一种实现,但已被`shared_ptr`和`weak_ptr`取代。这些智能指针基于RAII(Resource Acquisition Is Initialization)原则,即资源获取即初始化。RAII确保对象在其生命周期结束时自动释放资源。通过重载`*`和`-&gt;`运算符,可以方便地访问和操作智能指针所指向的对象。
|
2月前
|
C++
C++(九)this指针
`this`指针是系统在创建对象时默认生成的,用于指向当前对象,便于使用。其特性包括:指向当前对象,适用于所有成员函数但不适用于初始化列表;作为隐含参数传递,不影响对象大小;类型为`ClassName* const`,指向不可变。`this`的作用在于避免参数与成员变量重名,并支持多重串联调用。例如,在`Stu`类中,通过`this-&gt;name`和`this-&gt;age`明确区分局部变量与成员变量,同时支持链式调用如`s.growUp().growUp()`。