std :: bind () — извлечение базовой защищенной функции-члена из функции-члена производного класса

я бы хотел 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 );
}
};

Почему несоответствие в поведении? Что правильно? Какой обходной путь доступен для компиляторов, выдающих ошибки?

11

Решение

Ответ: смотри 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() {}
};
9

Другие решения

Это не имеет ничего общего с 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!
}
9

По вопросам рекламы [email protected]