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

发布于 2024-11-04 13:44:11 字数 641 浏览 10 评论 0原文

此代码:

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 code:

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

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

gives this error:

t.cpp: In member function 'void D::Bar()':
Line 3: error: 'void B::Foo()' is protected
  • Why can I call a protected method but not take its address?
  • Is there a way to mark something fully accessible from derived classes rather than only accessible from derived classes and in relation to said derived class?

BTW: This looks related but what I'm looking for a reference to where this is called out in the spec or the like (and hopefully that will lead to how to get things to work the way I was expecting).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

月下客 2024-11-11 13:44:11

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

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

但这不会编译(你的代码):< a href="http://www.ideone.com/OpxUy">http://www.ideone.com/OpxUy


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

您不能通过编写 &B::Foo 来获取其地址,因为 Foo 是一个受保护的成员,您无法从外部访问它< code>B,甚至没有它的地址。但是写&D::Foo,就可以了,因为Foo通过继承成为了D的成员,可以获取它的地址,无论是私有的、受保护的还是公共的。

&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

You can take the address through D by writing &D::Foo, instead of &B::Foo.

See this compiles fine : http://www.ideone.com/22bM4

But this doesn't compile (your code) : http://www.ideone.com/OpxUy


Why can I call a protected method but not take its address?

You cannot take its address by writing &B::Foo because Foo is a protected member, you cannot access it from outside B, not even its address. But writing &D::Foo, you can, because Foo becomes a member of D through inheritance, and you can get its address, no matter whether its private, protected or public.

&B::Foo has same restriction as b.Foo() and pB->Foo() has, in the following code:

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

See error at ideone : http://www.ideone.com/P26JT

↙温凉少女 2024-11-11 13:44:11

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

This is because an object of a derived class can only access protected members of a base class if it's the same object. Allowing you to take the pointer of a protected member function would make it impossible to maintain this restriction, as function pointers do not carry any of this information with them.

早茶月光 2024-11-11 13:44:11

我相信 protected 并不像您想象的那样在 C++ 中工作。在 C++ 中,受保护的仅允许访问其自身实例的父成员,而不是父类的任意实例。正如其他答案中所指出的,获取父函数的地址会违反这一点。

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

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

I believe protected doesn't work the way you think it does in C++. In C++ protected only allows access to parent members of its own instance NOT arbitrary instances of the parent class. As noted in other answers, taking the address of a parent function would violate this.

If you want access to arbitrary instances of a parent, you could have the parent class friend the child, or make the parent method public. There's no way to change the meaning of protected to do what you want it to do within a C++ program.

But what are you really trying to do here? Maybe we can solve that problem for you.

君勿笑 2024-11-11 13:44:11

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

这个问题有一个错误。您也无法进行调用

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

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


作为摘要,请阅读此问题报告

Why can I call a protected method but not take its address?

This question has an error. You cannot do a call either

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

As another answer says if you access the non-static protected member by a D, then you can. Maybe you want to read this?


As a summary, read this issue report.

木落 2024-11-11 13:44:11

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

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);

  }
}

Your post doesn't answer "Why can I
call a protected method but not take
its address?"

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);

  }
}
怪我入戏太深 2024-11-11 13:44:11

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

是的,使用 密码习惯用法。 :)

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()); }
};

由于只有 衍生 可以访问 衍生_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
}

请参阅Ideone 上的完整示例

Is there a way to mark something fully accessible from derived classes rather than only accessible from derived classes and in relation to said derived class?

Yes, with the 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()); }
};

Since only derived has access to the contructor of derived_key, only that class can call the foo method, even though it's public.
The obvious problem with that approach is the fact, that you need to friend every possible derived class, which is pretty error prone. Another possible (and imho better way in your case) is to friend the base class and expose a protected get_key method.

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
}

See the full example on Ideone.

撩心不撩汉 2024-11-11 13:44:11

标准参考: 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
  }
};

Standard reference: 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
  }
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文