【问题标题】:Access to method pointer to protected method?访问受保护方法的方法指针?
【发布时间】:2011-08-14 21:52:35
【问题描述】:

这段代码:

class B {
 protected:
  void Foo(){}
}

class D : public B {
 public:
  void Baz() {
    Foo();
  }
  void Bar() {
    printf("%x\n", &B::Foo);
  }
}

给出这个错误:

t.cpp: In member function 'void D::Bar()':
Line 3: error: 'void B::Foo()' is protected
  • 为什么我可以调用受保护的方法但不能获取其地址?
  • 有没有办法标记可以从派生类完全访问的东西,而不是只能从派生类访问与所述派生类相关的东西?

顺便说一句:This looks related 但我正在寻找一个参考,以说明在规范或类似内容中调用它的位置(希望这将导致如何让事情按我预期的方式工作)。

【问题讨论】:

    标签: c++ protected specifications


    【解决方案1】:

    这是因为派生类的对象只有在同一个对象时才能访问基类的受保护成员。允许您获取受保护成员函数的指针将无法维持此限制,因为函数指针不携带任何此类信息。

    【讨论】:

    • 我不想要那个限制。有没有办法让事情按照我的预期工作? (见编辑)
    • @BCS 我不太确定为什么首先存在相同对象的限制。一个关于你试图用这个完成什么的线索会很有帮助。
    • @BCS 实际上说不,因为您要求的是对 C++ 标准的更改。您总是可以分叉一个 C++ 编译器并对其进行修改以允许这样的构造,但它不再是 C++。
    • @BCS - 如果你被允许做你想做的事,protected 关键字实际上是没有用的,因为任何人都可以通过派生一个虚拟类来访问其他类的受保护部分创建一个指向成员的指针。按照设计,这是行不通的!
    【解决方案2】:

    你可以通过D获取地址,写&D::Foo,而不是&B::Foo

    看到这个编译正常:http://www.ideone.com/22bM4

    但这不能编译(你的代码):http://www.ideone.com/OpxUy


    为什么我可以调用受保护的方法但不能获取其地址?

    你不能通过写&B::Foo来获取它的地址,因为Foo是一个受保护的成员,你不能从B外部访问它,甚至它的地址也不能。但是写&D::Foo是可以的,因为Foo通过继承成为D的成员,无论是private、protected还是public,你都可以得到它的地址。

    &B::Foob.Foo()pB->Foo() 具有相同的限制,代码如下:

    void Bar() {
        B b;
        b.Foo();     //error - cannot access protected member!
        B *pB = this;
        pB->Foo();   //error - cannot access protected member!
      }
    

    在 ideone 看到错误:http://www.ideone.com/P26JT

    【讨论】:

    • 您的帖子没有回答“为什么我可以调用受保护的方法但不能获取其地址?”。
    • 出于复杂的原因,我现在不想(从词法上)引用 Derived 类。
    • @Prasoon:人们希望海报能够发布完整的答案...我会说“好期待”。但我会在我知道的范围内回答。
    • @Prasoon:+1 表示答案不完整。 { GodwinsLaw::Invoke(); }
    • @第一行:出于某种原因,我不知道这是可能的。凉爽的!因此,除了所有人对完整性的抱怨之外,即使在您进行编辑之前,您的回答也会告诉我一些有用的东西。
    【解决方案3】:

    我相信protected 在 C++ 中的工作方式与您认为的不同。在 C++ 中,protected 只允许访问 它自己的实例的父成员,而不是父类的任意实例。如其他答案所述,获取父函数的地址会违反这一点。

    如果您想访问父类的任意实例,您可以让父类成为子类的朋友,或者将父方法设为public。无法更改 protected 的含义以在 C++ 程序中执行您希望它执行的操作。

    但是您真正想在这里做什么?也许我们可以为您解决那个问题。

    【讨论】:

    • 公开事物允许非派生类访问(不好)。使用friend 要求B 的作者提前了解所有派生类(不好),并且还允许他们访问不应访问的东西(不好)。
    【解决方案4】:

    为什么我可以调用受保护的方法但不能获取它的地址?

    这个问题有一个错误。你也不能打电话

    B *self = this;
    self->Foo(); // error either!
    

    正如另一个答案所说,如果您通过D 访问非静态受保护成员,那么您可以。也许您想阅读this


    作为摘要,请阅读this issue report

    【讨论】:

      【解决方案5】:

      您的帖子没有回答“为什么我可以 调用受保护的方法但不采取 地址?”

      class D : public B {
       public:
        void Baz() {
          // this line
          Foo();
          // is shorthand for:
          this->Foo();
        }
        void Bar() {
          // this line isn't, it's taking the address of B::Foo
          printf("%x\n", &B::Foo);
      
          // not D:Foo, which would work
          printf("%x\n", &D::Foo);
      
        }
      }
      

      【讨论】:

      • 从语言纯粹主义者的角度来看,这可能是正确的/相关的,但在机器级别的事实是函数 F::FooD::Foo 是同一件事(证明:派生类甚至可以跨单独编译调用受保护的基类方法)。
      • @BCS - 是的,但只有当你确实有一个 D 对象时,你才能访问 D::Foo。您不能使用该指针来访问属于任何其他类的 Foo 。这是故意的!
      • 我的断言是D::Foo B::Foo(在幕后)所以在这种情况下,我有两种方法来做最终做同样事情的事情只有一个是合法的。如果从 CPU 上实际发生的情况来看,这似乎非常做作。实际上,我在抱怨 C++ 选择作为它的引用方法的东西对我的口味来说不够低级。
      【解决方案6】:

      有没有办法标记可以从派生类完全访问的东西,而不是只能从派生类访问并且与所述派生类相关?

      是的,使用passkey idiom。 :)

      class derived_key
      {
          // Both private.
          friend class derived;
      
          derived_key() {}
      };
      
      class base
      {
      public:
          void foo(derived_key) {}
      };
      
      class derived : public base
      {
      public:
          void bar() { foo(derived_key()); }
      };
      

      由于只有derived 可以访问derived_key 的构造函数,因此只有该类可以调用foo 方法,即使它是公开的。
      这种方法的一个明显问题是,您需要为每个可能的派生类加好友,这很容易出错。另一种可能(在您的情况下也是更好的方法)是与基类为朋友并公开受保护的 get_key 方法。

      class base_key
      {
          friend class base;
      
          base_key() {}
      };
      
      class base
      {
      public:
          void foo(base_key) {}
      
      protected:
          base_key get_key() const { return base_key(); }
      };
      
      class derived1 : public base
      {
      public:
          void bar() { foo(get_key()); }
      };
      
      class derived2 : public base
      {
      public:
          void baz() { foo(get_key()); }
      };
      
      int main()
      {
        derived1 d1;
        d1.bar(); // works
        d1.foo(base_key()); // error: base_key ctor inaccessible
        d1.foo(d1.get_key()); // error: get_key inaccessible
      
        derived2 d2;
        d2.baz(); // works again
      }
      

      查看完整示例 on Ideone

      【讨论】:

        猜你喜欢
        • 2020-07-26
        • 1970-01-01
        • 2014-12-19
        • 2012-08-06
        • 2014-12-29
        • 2013-04-06
        • 2014-10-31
        • 1970-01-01
        • 2020-05-02
        相关资源
        最近更新 更多