C++ Pointer-Like Classes,C++的指针类
2016-02-15 23:13
232 查看
所谓pointer-like class(像指针的类,下文简称为指针类),是指一个类被设计成像指针一样,可以当成指针来使用。为什么有了传统的指针还需要指针类?这是由于我们想在指针的基础上多做一点东西,或者说,我们想对指针有更多的控制或者让指针支持额外的功能。
下面介绍两类常见的指针类:智能指针和迭代器。
可以看到,shared_ptr里面包含了一个真正的指针px,这个指针会指向实际所指的对象。另外,shared_ptr还模拟了指针的的*和->操作,这通过操作符重载实现。下面的代码展示了shared_ptr的使用方法。
上面的代码声明了一个智能指针sp,并通过->操作符来调用成员函数。
下面的代码示例以链表的迭代器(__list_iterator)为例,展示了迭代器的特点。
链表(双向链表)的数据结构如下图所示。
链表的结点包含三个部分,分别前一个结点的指针,后一个结点的指针,以及数据。
迭代器
由于
首先,我们声明一个
通过
我们把上面的有关代码摘录如下:
参考资料:
1. 侯捷《C++最佳编程实践》视频,极客班,2015
2. 《C++ Primer》第15.6节,第三版,2002,潘爱民等译
下面介绍两类常见的指针类:智能指针和迭代器。
智能指针
对于传统的指针,我们可以使用两个操作符,即*解引用操作符,->成员访问操作符。一个类要设计成智能指针类,则也要提供这两个操作。这可以通过对类的操作符重载实现。namespace ll { template<class T> class shared_ptr { public: T& operator* () const { return *px; } T* operator->() const { return px; } shared_ptr(T* p): px(p) {} private: T *px; }; }
可以看到,shared_ptr里面包含了一个真正的指针px,这个指针会指向实际所指的对象。另外,shared_ptr还模拟了指针的的*和->操作,这通过操作符重载实现。下面的代码展示了shared_ptr的使用方法。
struct Foo { void method() { cout << "method" << endl; } }; ll::shared_ptr<Foo> sp(new Foo); // 定义了一个指向Foo类型的智能指针 Foo f(*sp); // 定义了一个Foo对象,并使用智能指针sp所指向的对象来进行初始化 f.method(); // 通过对象f调成成员函数 sp->method(); // 见下面的解释
上面的代码声明了一个智能指针sp,并通过->操作符来调用成员函数。
sp->method();会首先调用操作符函数
operator->() const,得到智能指针内部真实的指针
px,然后再通过
px调用method函数(
px->method())。在这里,可能大家有个疑问,即
sp->通过调用操作符函数
operator->()已经消耗了一个
->符号,
px->method()的
->是怎么来的呢?C++规定,对于调用
->操作符后,
->操作符并不消耗掉,而是会继续作用下去。这样一来,
sp->method();便等同于
sp->method();。
迭代器
迭代器也可以认为是上面所说的智能指针,不过迭代器除了提供*和
->操作外,还需要提供
++,
--的操作。
下面的代码示例以链表的迭代器(__list_iterator)为例,展示了迭代器的特点。
namespace ll { template<class T> struct __list_node { void *prev; void *next; T data; }; template<class T, class Ref, class Ptr> struct __list_iterator { typedef __list_iterator<T, Ref, Ptr> self; typedef Ptr pointer; typedef Ref reference; typedef __list_node<T>* link_type; link_type node; reference operator*() const { return (*node).data; } pointer operator->() const { return &(operator*()); } self& operator++() { node = (link_type)((*node).next); return *this; } self& operator--() { node = (link_type)((*node).prev); return *this; } }; }
链表(双向链表)的数据结构如下图所示。
链表的结点包含三个部分,分别前一个结点的指针,后一个结点的指针,以及数据。
迭代器
__list_iterator包含一个真实的指针
node,用来指向链表中的结点。可以看到,
__list_iterator除了提供
*和
->操作,还提供了
++,
--操作。对迭代器进行
++操作,会指向下一个元素,对迭代器进行
--操作,会指向前一个元素。
由于
node只是指向整个结点,为了取得结点的数据,还需要这样调用
(*node).data。
__list_iterator的使用的示例代码如下。
struct Foo { void method() { cout << "method" << endl; } }; ll::__list_iterator<Foo, Foo&, Foo*> iter; *iter; // 获得一个Foo对象 iter->method(); // 意思是调用Foo::method(),相当于(*iter).method(),也相当于(&(*iter))->method()
首先,我们声明一个
__list_iterator迭代器
iter。我们知道迭代器也是一种指针类,所以可以模拟指针的操作。
通过
*操作符,我们可以得到一个
Foo对象。
iter->method();则调用
Foo::method(),这个语句复杂一点,解释如下。
我们把上面的有关代码摘录如下:
reference operator*() const { return (*node).data; } pointer operator->() const { return &(operator*()); }
iter->method();会首先调用
operator->() const函数,由于
operator->() const里面还会调用
operator*()先取得
data,然后再取地址,所以
operator->() const会返回data的地址。在上例中,亦即是
Foo对象的地址。这样,通过
->操作符,便可以调用到
Foo::method()。
参考资料:
1. 侯捷《C++最佳编程实践》视频,极客班,2015
2. 《C++ Primer》第15.6节,第三版,2002,潘爱民等译
相关文章推荐
- leetcode - Minimum Height Trees
- C语言之回文数算法
- C语言之回文数算法
- C语言之回文数算法
- bzoj 2555 Substring
- 【POJ 1451】T9 中文题意&题解&代码(c++)
- 不用局部变量实现C语言两数交换算法
- 不用局部变量实现C语言两数交换算法
- C语言代码优化
- 不用局部变量实现C语言两数交换算法
- C语言字符串的常见特殊操作(除了string.c实现的那些接口)
- C语言字符串的常见特殊操作(除了string.c实现的那些接口)
- C语言字符串的常见特殊操作(除了string.c实现的那些接口)
- C++视频课程小结(3)
- C++之路进阶——最小费用最大流(美食节)
- C++之路进阶——最大流(善意的投票)
- 【C语言】调整数组顺序使奇数位于偶数前面
- C++之路进阶——最小费用最大流(支线剧情)
- C++三大继承与多级派生
- C++之路进阶——矩阵乘法(Xn数列)