【问题标题】:How do pointers to members in C++ work internally?指向 C++ 中成员的指针如何在内部工作?
【发布时间】:2019-09-10 18:32:54
【问题描述】:

我想知道指向成员的指针在 C++ 中是如何工作的。

我查看了一些地方,发现它们存储了某种偏移量。并使用成员在内存中的出现顺序与它们在类/结构定义中声明的顺序相同的事实。但是......

#include <iostream>
#include<typeinfo>
using namespace std;
struct S
{
    S(int n): mi(n) {}
    int mi;
    int k;
    int f()  {return mi+k;}
};

int main()
{
    S s(7);
    int S::*pmi = &S::mi;
    int S::*lop = &S::k;
    int (S::*sf)() = &S::f;
    cout<<&S::mi<<endl<<&S::k<<endl<<&S::f<<endl<<pmi<<endl<<lop<<endl<<sf<<endl;
    cout<<typeid(lop).name()<<endl;
}

我预计会看到某种偏移量。但是,第一行中所有带有 cout

我不明白,如果所有人都给出 1,那么关于偏移量的信息存储在哪里?

如果你能解释到底发生了什么,那将非常有帮助。

【问题讨论】:

  • 不确定,可能是误会。我将删除我的评论,因为 eeroikas 的回答已经提到了我真正追求的东西。

标签: c++ pointers datamember


【解决方案1】:

Iostreams 插入操作符对于指向成员的指针没有重载。

然而,bool 存在重载,指向成员的指针可隐式转换为 bool - 指向成员的空指针将转换为 false,否则为 true。 bool 如果为 true,则流式传输为 1,如果为 false,则流式传输为 0。所以你观察到的输出是你指向成员的指针都不是空的。

我尝试增加 ++.. 但这也不起作用..

递增不起作用,因为指向成员的指针不支持指针运算。

那么,有什么方法可以实际查看偏移值吗?

任何东西都可以作为字节数组来观察,所以你可以通过一个小辅助函数来惊叹成员指针的内容:

template<class T>
void print_raw(const T& obj) {
    const unsigned char* cptr = reinterpret_cast<const unsigned char*>(&obj);
    const unsigned char* end = cptr + sizeof(T);
    while(cptr < end) {
        printf("%02hhx ", *cptr++); // is there simple way with iostreams?
    }
    std::cout << '\n';
}

std::cout << "pmi: ";
print_raw(pmi);
std::cout << "lop: ";
print_raw(lop);
std::cout << "sf:  ";
print_raw(sf);

我的系统上的示例输出:

pmi: 00 00 00 00 00 00 00 00 
lop: 04 00 00 00 00 00 00 00 
sf:  f0 08 40 00 00 00 00 00 00 00 00 00 00 00 00 00 

这可能会让您了解编译器是如何实现它们的。请注意,如果实现包含任何填充字节/位,则它们可能具有任何值,因此任何非零值都可能毫无意义。

成员对象指针输出看起来很明显。它看起来像是对象中的一个小端 64 位偏移量。 mi 位于偏移量 0 处,k 位于偏移量 4 字节处。

【讨论】:

  • 好的。那么,有什么方法可以查看它们实际存储的内容吗?或者他们实际上是如何工作的?我尝试增加 ++.. 但这也不起作用..
  • 那么,有什么方法可以实际查看偏移值吗??
  • 欣赏编辑。比“标准没有指定这一点”更进一步和有用。我们需要更多这样的答案。
  • 非常感谢。愿上帝保佑你! :)
  • 对不起,我忘了..我第一次来这里..我做到了:)
【解决方案2】:

iostreams 不能直接打印指向成员的指针。

但是,任何指针都可以转换为布尔值。

它恰好是使std::cout::operator&lt;&lt; 工作的唯一可能的转换,所以它不是模棱两可的。

你的代码相当于这样:

    cout 
        << static_cast<bool>(&S::mi) << endl
        << static_cast<bool>(&S::k) << endl
        << static_cast<bool>(&S::f) << endl

【讨论】:

    猜你喜欢
    • 2018-03-24
    • 2013-05-02
    • 1970-01-01
    • 2021-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-08
    • 1970-01-01
    相关资源
    最近更新 更多