Возможность использовать указатель для функции вызова частного метода внешнего класса
Основываясь на следующем ответе на недавний вопрос, я могу использовать указатель на функцию, чтобы вызвать частный метод Foo<T>::foo()
из другого класса Bar
, как показано ниже (см. Также ideone)
#include <iostream>
template<typename T>
struct Bar
{
typedef void (T::*F)();
Bar( T& t_ , F f ) : t( t_ ) , func( f )
{
}
void operator()()
{
(t.*func)();
}
F func;
T& t;
};
template<typename T>
class Foo
{
private:
void foo()
{
std::cout << "Foo<T>::foo()" << std::endl;
}
public:
Foo() : bar( *this , &Foo::foo )
{
bar();
}
Bar<Foo<T> > bar;
};
int main()
{
Foo<int> foo;
}
Это работает на MSVC 2013 и GCC 4.8.3. Это действительно?
Ответы
Ответ 1
Да, это допустимо, и это работает.
C++ Программирование Bjarne Stroustoup
C++ защищает от атак, а не за умышленное обход (мошенничество)
Конечно, вы не можете напрямую/легко вызывать частные методы вне класса, но если вы приложите достаточные усилия, C++ позволит это.
Ответ 2
C++ стандарт говорит
11.1. Член класса может быть
(1.1) - частный; то есть его имя может использоваться только членами и друзьями класса, в котором он объявлен.
т.е. спецификатор доступа применяется к имени, а не к исполняемому коду. Это имеет смысл, если вы думаете об этом, поскольку спецификаторы доступа являются конструкцией времени компиляции.
Ответ 3
Да, это действительно так.
Bar.operator()()
просто использует указатель, не пытаясь использовать идентификатор с спецификатором частного доступа.
Не имеет значения, как был инициализирован этот указатель, если он указывает на правильную функцию.
В качестве примера рассмотрим следующее:
#include <iostream>
struct A {
protected:
void hidden() { std::cout << "But I was hidden !?\n"; }
};
struct B : A {
using A::hidden; // Making it public
};
int main() {
B().hidden();
}
В стороне, не используйте std::endl
если вы действительно не хотите очищать поток, как это дорого.
Обычно '\n'
достаточно.
Ответ 4
Это имеет значение.
Файл заголовка
class A;
typedef int (A::*handler)(int x);
struct handler_pair {
int code,
handler fn
}
class A {
...
private:
int onGoober(int x);
int onGomer(int x);
};
Исходный файл
handler_pair handler_map[] = {
{0, &A::onGoober}, // these will complain about the method being private
{1, &A::onGomer}
};
Изменение handler_map на статический член в классе и инициализация таким образом позволяет избежать жалобы.
Если вы берете адрес функции-члена, важно.