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

时间:2011-04-28 17:10:29

标签: c++ protected specifications

此代码:

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但是我正在寻找一个参考指标或类似内容的参考(希望这将导致如何按照我期望的方式工作)

6 个答案:

答案 0 :(得分:20)

您可以通过D代替&D::Foo来填写&B::Foo地址。

看到这个编译很好:http://www.ideone.com/22bM4

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


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

您无法通过撰写&B::Foo来获取其地址,因为Foo受保护的成员,您无法从外部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

答案 1 :(得分:5)

这是因为派生类的对象只能访问基类的受保护成员(如果它是相同的对象)。允许您使用受保护成员函数的指针将使得无法保持此限制,因为函数指针不会随身携带任何此类信息。

答案 2 :(得分:3)

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

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

但是你真的试图在这做什么?也许我们可以为你解决那个问题。

答案 3 :(得分:3)

  

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

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

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

另一个答案是,如果您通过D然后访问非静态受保护成员,则可以。也许您想阅读this


总结一下,请阅读this issue report

答案 4 :(得分:1)

  

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

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

  }
}

答案 5 :(得分:0)

  

有没有办法在派生类中标记完全可访问的内容,而不是只能从派生类中访问并与所述派生类相关?

是的,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