访问受保护方法的方法指针

Access to method pointer to protected method?

本文关键字:方法 指针 访问 受保护      更新时间:2023-10-16

代码:

class B {
 protected:
  void Foo(){}
}
class D : public B {
 public:
  void Baz() {
    Foo();
  }
  void Bar() {
    printf("%xn", &B::Foo);
  }
}

给出如下错误:

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

BTW:这看起来是相关的,但我正在寻找一个参考,在规范或类似的地方调用它(并希望这将导致如何让事情按照我期望的方式工作)。

可以通过写&D::Foo而不是&B::Foo来获取D的地址。

查看编译结果:http://www.ideone.com/22bM4

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


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

你不能通过写&B::Foo来获取它的地址,因为Foo是一个受保护的成员,你不能从B外部访问它,甚至不能访问它的地址。但是写&D::Foo,你可以,因为Foo通过继承成为D的成员,你可以得到它的地址,不管它是私有的、受保护的还是公共的。

&B::Foo具有与b.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

这是因为派生类的对象只有在与基类相同的情况下才能访问基类的受保护成员。如果允许使用受保护成员函数的指针,则不可能维护此限制,因为函数指针不携带任何此类信息。

我相信protected在c++中并不像你想象的那样工作。在c++中,protected只允许访问自己的实例的父成员,而不是父类的任意实例。如其他答案所述,取父函数的地址将违反此规则。

如果你想访问父类的任意实例,你可以让父类成为子类的好友,或者让父方法成为public。在c++程序中,没有办法改变protected的含义来做你想让它做的事情。

但是你在这里真正想要做什么呢?也许我们可以帮你解决那个问题

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

这个问题有错误。也不能调用

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

正如另一个答案所说,如果您通过D访问非静态受保护成员,可以。也许你想看看这个?


作为总结,请阅读此问题报告

你的帖子没有回答"为什么我可以。调用受保护的方法,但不使用它的地址吗?"

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("%xn", &B::Foo);
    // not D:Foo, which would work
    printf("%xn", &D::Foo);
  }
}

是否有一种方法来标记从派生类完全可访问的东西,而不是只能从派生类访问,并与所述派生类相关?

是的,使用passkey习语。:)

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
}

标准参考:https://en.cppreference.com/w/cpp/language/access#Protected_member_access

When a pointer to a protected member is formed, it must use a derived class in its declaration:
struct Base {
  protected:
    int i;
};
 
struct Derived : Base {
  void f() {
//  int Base::* ptr = &Base::i;    // error: must name using Derived
    int Base::* ptr = &Derived::i; // OK
  }
};