在C ++中,为什么指向类成员的指针包含偏移而不是地址?

时间:2017-07-26 17:37:53

标签: c++ offset pointer-to-member class-members

通常指针包含地址。为什么指向类成员的指针包含偏移量?

讨论指向类数据成员的指针,而不是指向成员函数的指针。

4 个答案:

答案 0 :(得分:7)

指向类成员的指针与常规指针的不同之处在于它本身并不指向内存中的单个位置。例如,如果您有此设置:

struct MyStruct {
    int x;
    int y;
};

int MyStruct::* ptr = &MyStruct::y;

然后指针ptr实际上并没有指向一个内存地址,因为没有一个对象MyStruct::y。相反,MyStruct的每个实例都有自己的数据成员y副本。

C ++标准并没有强制指向成员的指针是如何实现的,但是一个常见的策略是让指向成员的指针存储从对象基础到字段的字节偏移量。题。这样,当你写一些像

这样的东西
MyStruct ms;
ms.*ptr = 137;

编译器可以生成代码"转到ms的基址,跳过由ptr中存储的值指定的字节数,然后写入137。&# 34;

答案 1 :(得分:3)

指针不必包含地址。指针是间接访问某个对象的工具 - 即编写将访问编译时未知的对象的代码。例如:

a = 10; // It is known at compile time, 10 is written to object a
*pi = 10; // It is not known at compile time where 10 is written to

对于普通对象,在指针中使用地址是实现此目标的最便宜的方法(但是,它不会成为C ++脚本的情况!)。

对于会员来说,正常的地址不会起作用 - 没有班级成员的地址!只有拥有类对象时,才能知道成员的物理地址。

因此,您必须使用某种偏移量,一旦知道实际对象,您就可以将其转换为物理地址。

答案 2 :(得分:3)

指向成员的指针不是指针。

C ++类型系统包含几种复合类型,并且有两种独立的兄弟类型的复合类型彼此无关,尽管它们具有相似的声音名称:指针和“指向非静态类成员的指针“。我将后者称为“指向成员的指针”,用连字符来强调那些不是一种特殊的指针,但实际上它是完全分开的。

顺便说一下,类型特征库通过std::is_pointerstd::is_member_pointer分隔这两个概念。

这两种类型的用途完全不同:

  • 指针可以表示对象(或函数)的地址(或为null)。也就是说,给定一个可解引用的指针,它指向的是一个实际的具体事物。

  • 指向成员的指针表示从到非静态类成员的抽象引用。请注意,没有涉及对象。这样的指针值并没有指向任何具体的东西,它没有“解除引用”的概念。

重复最后一句:指向成员的指针不能被解除引用,并且它在任何意义上都不是对象的地址。相反,指向成员的指针(具体地说,指向数据成员)可以应用于其类的对象实例,而与对象一起选择子对象的子对象该对象对应于它所代表的类成员。 (指针到成员函数对应用于实例的概念略有不同;应用程序的结果是函数调用。)

最后回到你的问题:指针包含一个对象或函数的地址,因为它指向一个对象或函数。指向成员的指针不包含地址,因为它不指向任何地址;它代表了一种关系。

答案 3 :(得分:0)

与其他语言相反,常规C ++类成员所谓的&#34;一等公民&#34;,这意味着它们不是具有额外对象参数的常规函数​​/变量。< / p> 相反,他们与各自的班级密切相关。因此,指向成员的指针的声明总是包含它所属的类。如果这导致存储在指针中的类实例的偏移量或者未指定其他内容。

另一种情况是static班级成员。它们类似于类的命名空间中的全局函数/变量,最终具有protectedprivate访问限制。您可以检索指向static元素的指针,并像常规指针一样使用它们。