微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

通过限定名访问成员数据的地址会产生错误

如何解决通过限定名访问成员数据的地址会产生错误

正如我们所知,派生类 publicprotected 成员的直接或间接基类在派生类中可用。

所以我有这个例子:

struct Foo{int x_ = 10;};
struct Bar : Foo{};
struct FooBar : Bar{
    void f()const{
        std::cout << &x_ << " : " << x_ << '\n';
        std::cout << &Foo::x_ << " : " << Foo::x_ << '\n';
        std::cout << &Bar::x_ << " : " << Bar::x_ << '\n';
        std::cout << &FooBar::x_ << " : " << FooBar::x_ << '\n';
    }
};



int main(){
    FooBar fb{};
    fb.f();
}
  • 当我编译并运行程序时,我得到了输出

      0x7ffc2f7ca878 : 10
      1 : 10
      1 : 10
      1 : 10
    

那么为什么通过完全限定名称访问成员数据 A::x_ 的地址会产生“无效”地址?但是直接访问它(非限定查找)是可以的。

  • 我的程序是否处于未定义行为?

  • 我已经使用 GCC 和 CLANG 编译了我的程序。

解决方法

首先,您很可能不打算在每个 & 语句中重复 std::cout 运算符,因此我删除了每个重复的实例,以打印成员的值而不是其地址。

现在看这个:

#include <iostream>

struct Foo{int x_ = 10;};
struct Bar : Foo{};
struct FooBar : Bar
{
  void f()const
  {
    std::cout << &x_ << " : " << x_ << '\n';
    std::cout << &(Foo::x_) << " : " << Foo::x_ << '\n';
    std::cout << &(Bar::x_) << " : " << Bar::x_ << '\n';
    std::cout << &(FooBar::x_) << " : " << FooBar::x_ << '\n';
  }
};

int main(){
  FooBar fb{};
  fb.f();
}

输出:

0x7fffe136c594:10
0x7fffe136c594:10
0x7fffe136c594:10
0x7fffe136c594:10

一切正常!我更改的是将 Foo::x_ 之类的表达式括在括号中。为什么?由于 &Foo::x_ 使用内置地址运算符,请参阅 cppreference.com 中的 Member access operators。它的值是一个指向数据成员的指针,它不是一个普通的指针,因为它需要绑定到一个对象才能返回一个地址。另请参阅 Similar stackoverflow question 以获取更多说明。

编辑

您可能想知道为什么 std::cout 为指向成员的指针显示 1。这是因为隐式转换为 bool:

布尔转换
整型、浮点型、无作用域枚举、指针和成员指针类型的纯右值可以转换为 bool 类型的纯右值。

Quotation source

转换后的值当然是true,因为你的指针是有效的,只有nullptr(和0)被转换为false。根据其他规则,true 被转换为 1。Q.E.D.

,

我的程序是否处于未定义行为?

没有。行为定义明确。

那么为什么通过完全限定名称访问成员数据 A::x_ 的地址会产生“无效”地址?

您没有使用完全限定的名称。完全限定名称始终从全局命名空间开始。例如,::Foo::x_ 将是完全限定名称,而 Foo::x_ 则不是。

您也不会“访问”成员(除非您插入 x_)。在成员名称上应用一元运算符 & 时,结果是指向数据成员的指针。在 &Foo::x_ 的情况下,类型将是 int Foo::*,即指向 Foo 类型的 int 成员的指针。

此外,1 不一定是“无效”地址,但您观察到的根本不是地址。字符流没有接受指向数据成员的指针的流插入运算符。然而,它们确实有一个接受 bool 的重载,并且所有指向数据成员的指针都可以隐式转换为 bool,因此这种重载是重载决议的有效候选者。

由于指向相关数据成员的指针不为空,因此转换后的值为真。向字符流插入true时,输出为1。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。