Доступ к методу указателя на защищенный метод?
Этот код:
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
- Почему я могу вызвать защищенный метод, но не принимать его адрес?
- Есть ли способ отметить что-то полностью доступное из производных классов, а не только доступное из производных классов и в отношении указанного производного класса?
BTW: Это связано с, но я ищу ссылку на то, где это вызывается в спецификации или тому подобное (и, надеюсь, это приведет к как заставить вещи работать так, как я ожидал).
Ответы
Ответ 1
Вы можете взять адрес через D
, написав &D::Foo
вместо &B::Foo
.
См. этот компилятор отлично: 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
Ответ 2
Это связано с тем, что объект производного класса может обращаться только к защищенным членам базового класса, если он является одним и тем же объектом. Разрешение на использование указателя защищенной функции-члена сделает невозможным сохранение этого ограничения, поскольку указатели на функции не содержат никакой информации с ними.
Ответ 3
Я считаю, что protected
работает не так, как вы думаете, на С++. В С++ protected
разрешается только доступ к родительским членам собственного экземпляра НЕ произвольным экземплярам родительского класса. Как отмечалось в других ответах, обращение адреса родительской функции нарушило бы это.
Если вы хотите получить доступ к произвольным экземплярам родителя, у вас может быть родительский класс friend или его родительский метод public
. Невозможно изменить значение protected
, чтобы сделать то, что вы хотите, чтобы он делал в программе на С++.
Но что вы на самом деле пытаетесь сделать здесь? Возможно, мы сможем решить эту проблему для вас.
Ответ 4
Почему я могу вызвать защищенный метод, но не принимать его адрес?
У этого вопроса есть ошибка. Вы не можете позвонить либо
B *self = this;
self->Foo(); // error either!
Как говорится в другом ответе, если вы получаете доступ к нестационарному защищенному элементу с помощью D
, тогда вы можете. Может быть, вы хотите прочитать этот?
В качестве сводки прочитайте этот отчет.
Ответ 5
Ваше сообщение не отвечает "Почему я могу вызывать защищенный метод, но не принимать его адрес?"
class D : public B {
public:
void Baz() {
// this line
Foo();
// is shorthand for:
this->Foo();
}
void Bar() {
// this line isn't, it taking the address of B::Foo
printf("%x\n", &B::Foo);
// not D:Foo, which would work
printf("%x\n", &D::Foo);
}
}
Ответ 6
Есть ли способ отметить что-то полностью доступное из производных классов, а не только доступное из производных классов и в отношении указанного производного класса?
Да, с идентификатором 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
}
См. полный пример в Ideone.