я бы хотел bind()
к версии функции моего базового класса из производного класса. Функция помечена как защищенная в базе. Когда я это делаю, код успешно компилируется в Clang (Apple LLVM Compiler 4.1), но выдает ошибку как в g ++ 4.7.2, так и в Visual Studio 2010. Ошибка выглядит так: «Base :: foo»: не может доступ защищенного члена. «
Подразумевается, что контекст для ссылки на самом деле в bind()
где, конечно, функция рассматривается как защищенная. Но не должен bind()
наследовать контекст вызывающей функции — в этом случае Derived::foo()
— и поэтому видите базовый метод как доступный?
Следующая программа иллюстрирует проблему.
struct Base
{
protected: virtual void foo() {}
};
struct Derived : public Base
{
protected:
virtual void foo() override
{
Base::foo(); // Legal
auto fn = std::bind( &Derived::foo,
std::placeholders::_1 ); // Legal but unwanted.
fn( this );
auto fn2 = std::bind( &Base::foo,
std::placeholders::_1 ); // ILLEGAL in G++ 4.7.2 and VS2010.
fn2( this );
}
};
Почему несоответствие в поведении? Что правильно? Какой обходной путь доступен для компиляторов, выдающих ошибки?
Ответ: смотри boost :: bind с защищенными членами & контекст который цитирует эту часть стандарта
Дополнительная проверка доступа помимо тех, которые были описаны ранее в пункте 11
применяется, когда нестатический элемент данных или функция нестатического члена
является защищенным членом своего класса именования (11.2) 105) Как описано
ранее доступ к защищенному члену предоставляется, потому что ссылка
происходит в другом или члене некоторого класса C. Если доступ к форме
указатель на член (5.3.1), спецификатор вложенного имени должен называть C или
класс, производный от C. Все другие обращения включают (возможно,
неявное) объектное выражение (5.2.5). В этом случае класс
Выражение объекта должно быть C или классом, производным от C.
Обходной путь: сделать foo
public
функция-член
#include <functional>
struct Base
{
public: virtual void foo() {}
};
Это не имеет ничего общего с bind
, Из-за фрагмента стандарта @rhalbersma, который уже цитировался, выражение &Base::foo
является незаконным в недружелюбном члене Derived
в каждом контексте.
Но если ваше намерение было сделать что-то эквивалентное вызову Base::foo();
, у вас есть большая проблема: указатели на функции-члены всегда вызвать виртуальное переопределение.
#include <iostream>
class B {
public:
virtual void f() { std::cout << "B::f" << std::endl; }
};
class D : public B {
public:
virtual void f() { std::cout << "D::f" << std::endl; }
};
int main() {
D d;
d.B::f(); // Prints B::f
void (B::*ptr)() = &B::f;
(d.*ptr)(); // Prints D::f!
}