C++抽象编程——指针(2)——特殊的指针

来源:互联网 发布:java如何输出 编辑:程序博客网 时间:2024/06/03 17:45

指向结构体(类)的指针

前面部分中的示例仅声明指向基本类型的指针。 在C ++中,将指针与结构或对象结合使用是非常普遍的。 例如,声明:

Point pt(3, 4);Point *pp = &pt;

声明两个局部变量。变量是pt包含具有坐标值3和4的Point对象。变量pp包含指向同一Point对象的指针。使用基于指针的格式,这些声明产生的内存图如下所示:

从指针pp,你可以使用 * 运算符移动到对象。

所以 * pp和pt是有效的同义词。
但是,如果你尝试引用给定指向该对象的成员和方法,则需要谨慎。 例如,你不能通过下面的写入获取点的x坐标:

*pp.getX()

虽然代码看起来正确,但在此表达式中运算符的优先级存在问题。 在C ++中,点运算符的优先级高于星号运算符,这意味着编译器尝试将该表达式解释为:

*(pp.getX())

这是没有意义的。因为你想做的是首先引用指针,然后调用该方法,这意味着该语句需要括起来,如下所示:

(*pp).get();

这个表达式虽然具有期望的效果,但是对于日常使用来说太麻烦了。当你编写更复杂的应用程序时,你会发现自己一直使用指向对象的指针。强制程序员在每个选择操作中包括这些括号会使指向对象的指针不那么方便。为了消除一些不便之处,C ++定义了操作符 - >,它将取消引用和选择的操作组合到一个操作符中。 因此,给定指针变量pp的调用getX方法的常规方法是:

pp->getX();

this 关键字

当你编写类的实现时,C++将关键字this定义为当前对象的指针。这个关键字在应用中很是广泛,以后可以看到。其中最常见的一个是你可以使用关键字 this 来选择对象的实例变量,即使这些名称被参数或局部变量遮盖。
介绍了Point类的构造函数的上下文中引入了showdown的问题,这在当时看起来是这样的:

Point(int cx, int cy) {    x = cx;    y = cy;}

该构造函数中的参数必须被命名为x和y以外的其他参数,以避免与实例变量的名称冲突。然而,用户可能会发现新的名字有点混乱。从用户的角度来看,x和y正好是构造函数参数的正确名称。然而,从实现者的角度来看,x和y是实例变量的完美名称。
使用关键字this选择实例变量可以同时满足客户端和实现者,如下所示:

Point(int x, int y) {    this->x = x;    this->y = y;}

一些程序员认为,使用这个对当前对象的成员的每个引用使得代码更容易阅读。 对于所有这些引用,JavaScript语言至关重要。但是我们这里注意,只有当这样做有助于解决歧义时才使用它。

特殊的空指针(NULL)

在许多指针应用程序中,有一个特殊的指针值是有用的,它指示指针实际上并不涉及任何有效的内存地址。该特殊值称为空指针(null pointer),并在内部表示为值0. 在C ++中,指示空指针的最佳方法是使用常量NULL,它被定义在< cstddef >接口中。
在空指针上使用 * 运算符是非法的。当今使用的流行编程环境通常会检测到该错误并终止程序,但不能保证该响应。在某些机器上,尝试读取空指针的目标值只是给出机器中0000的内容。在未初始化指针的情况下,情况大致相同。 如果你声明一个指针但未能初始化它,则计算机将尝试将该指针的内容解释为地址,并尝试读取该内存区域。在这种情况下,程序可能会以非常难以检测的方式失败。
空指针的使用将以后提及。现在,重要的是要记住这个常数存在。

指针和引用调用

下图中的程序提供了C ++如何通过引用实现调用的简单说明。 该程序从用户读取两个整数,然后检查它们是否按升序排列。 如果没有,程序调用函数swap,它交换其参数的值。

#include <iostream>using namespace std;/* Function prototype */void swap(int & x, int & y);/* Main program */int main() {    int n1;    cout << "Enter n1: ";    cin >> n1;    int n2;    cout << "Enter n2: ";    cin >> n2;    if (n1 > n2) swap(n1, n2);        cout << "The range is " << n1 << " to " << n2 << "." << endl;    return 0;}/** Function: swap* Usage: swap(x, y);* ------------------* Exchanges the values of x and y. The arguments are passed by* reference and can therefore be modified.*/void swap(int & x, int & y) {    int tmp = x;    x = y;    y = tmp;}

假设你输入的两个数分别是20和10.

这些值是无序的,所以主程序会调用swap。 紧接在该调用之前的堆栈的内容如下所示:

函数swap通过引用获取其参数,这意味着swap的栈被赋予调用参数的地址(addresses)而不是值。在调用之后,栈的内容如下所示:

对swap中的x和y的所有引用都被传递给变量n1和n2,变量n1和n2是指针的目标。 交换这些值意味着在调用swap返回后,此函数的效果仍然存在,此时栈看起来像这样:

所以导致下面的输出:

虽然通过引用调用非常方便,但它不是C ++语言的基本特征。 您可以通过引用指针来模拟调用的效果。 在这个程序中,你所要做的就是将交换的实现改为:

void swap(int *px, int *py) {    int tmp = *px;    *px = *py;    *py = tmp;}

然后调用主函数:

swap(&n1, &n2);

我们将使用通过引用调用的程序转换为基于指针的等效项。

阅读全文
0 0
原创粉丝点击