类成员指针
成员指针是指可以指向类的非静态成员的指针。
一般情况下,指针指向一个对象,但是成员指针指示的是类的成员,而非类的对象。
类的静态成员不属于任何对象,因此无须特殊的指向静态成员的指针,指向静态成员的指针与普通指针没有什么区别。
成员指针的类型囊括了类的类型以及成员的类型。
当初始化一个这样的指针时,我们令其指向类的某个成员,但是不指定该成员所属的对象:直到使用成员指针时,才提供成员所属的对象。
为了解释成员指针的原理,我们定义下面这个类:
class Screen
{
public:
typedef std::string::size_type pos;
char get_cursor() const
{
return contents[cursor];
}
char get() const;
char get (pos ht, pos wd) const;
private:
std::string contents;
pos cursor;
pos height, width;
};
数据成员指针
和其他指针一样,在声明成员指针时我们也使用*来表示当前声明的名字是一个指针。
与普通指针不同的是,成员指针还必须包含成员所属的类。
因此,我们必须在*之前添加classname::以表示当前定义的指针可以指向classname的成员。
例如:
// pdata可以指向一个常量(非常量)Screen对象的string成员
const string Screen:: *pdata;
上述语句将pdata 声明成“一个指向Screen类的const string成员的指针”。
常量对象的数据成员本身也是常量,因此将我们的指针声明成指向const string 成员的指针意味着pdata可以指向任何Screen对象的一个成员,而不管该Screen对象是否是常量。
作为交换条件,我们只能使用pdata读取它所指的成员,而不能向它写入内容。
当我们初始化一个成员指针(或者向它赋值)时,需指定它所指的成员。
例如,我们可以令pdata指向某个非特定Screen对象的contents成员:(前提是contents成员不是私有的)
pdata =&Screen::contents;
其中,我们将取地址运算符作用于Screen类的成员而非内存中的一个该类对象。
当然,在C++11 新标准中声明成员指针最简单的方法是使用auto或decltype:
auto pdata = &Screen::contents;
使用数据成员指针
读者必须清楚的一点是,当我们初始化一个成员指针或为成员指针赋值时,该指针并没有指向任何数据。
成员指针指定了成员而非该成员所属的对象,只有当解引用成员指针时我们才提供对象的信息。
与成员访问运算符 . 和->类似,也有两种成员指针访问运算符:.*和->*,这两个运算符使得我们可以解引用指针并获得该对象的成员:
Screen myScreen, *pScreen =&myScreen;
//.*解引用pdata以获得myScreen 对象的 contents成员
auto s = myScreen. *pdata;
//->*解引用pdata以获得pScreen 所指对象的 contents成员
s = pScreen->*pdata;
从概念上来说,这些运算符执行两步操作:它们首先解引用成员指针以得到所需的成员;然后像成员访问运算符一样,通过对象(.*)或指针(->*)获取成员。
像下面这样子使用数据成员指针
const string Screen::* pdata = &Screen::contents;
Screen a;
auto b = a.*pdata;
返回数据成员指针的函数
常规的访问控制规则对成员指针同样有效。
例如,Screen的contents成员是私有的,因此之前对于pdata的使用必须位于Screen类的成员或友元内部,否则程序将发生错误。
因为数据成员一般情况下是私有的,所以我们通常不能直接获得数据成员的指针。