Подтвердить что ты не робот

Указатель на функцию-член в недоступной базе

Компиляция следующего примера:

class A
{
  public:
    void foo()
    {
    }
};

class B : private A
{
  public:
    using A::foo;
};

int main()
{
    typedef void (B::*mf)();
    mf func = &B::foo;

    B b;
    (b.*func)();
}

не удается выполнить следующие ошибки:

main.cpp||In function ‘int main()’:  
main.cpp|18|error: ‘A’ is an inaccessible base of ‘B’  
main.cpp|18|error:    in pointer to member function conversion

Я понимаю, что A не является доступной базой B, но я использую ключевое слово using. Не следует ли разрешить доступ к функции foo?

Каковы соответствующие параграфы в стандарте, которые предотвращают компиляцию вышеуказанного?

4b9b3361

Ответ 1

Доступ к членам A регулируется главой 11 "Контроль доступа пользователей", но конверсии между указателями и членами покрываются 4.11. В частности, 4.11/2 заявляет, что вы не можете преобразовать T A::* в T B::*, если вы не можете преобразовать B* в A*.

Здесь небольшое изменение вопроса:

class A
{
  public:
    void foo()
    {
    }
};

class B : private A
{
  public:
    using A::foo;
};

int main()
{
    typedef void (A::*amf)();
    typedef void (B::*bmf)();
    amf func = &A::foo;
    bmf f2 = static_cast<bmf>(func);
}

Мы все еще говорим о той же функции. Это не поиск имени B::foo, который терпит неудачу (using позаботится об этом), это тот факт, что тип B::foo равен void A::*(), который не может быть преобразован в void B::*().

Ответ 2

Так как foo in B наследуется от A, &B::foo идентичен &A::foo и имеет тип void (A::*)(). Когда вы пишете

typedef void (B::*mf)();
mf func = &B::foo;

вы пытаетесь преобразовать из void (A::*)() в void (B::*)(). Поскольку B наследуется в частном порядке от A, вы не можете этого сделать.

Ответ 3

Я упростил проблему. Основная проблема приведена ниже:

int main() 
{ 
    &B::foo; 
}

Здесь я пытаюсь получить доступ к адресу foo, который определен в классе A и унаследован в частном порядке. Поэтому он дает ошибку компиляции.

Использование только импорта функции. Он не изменяет спецификатор доступа foo.