Вызов функции защищенного базового класса из вложенной структуры

Обычно вложенные структуры имеют доступ к классам-владельцам. public, protected а также public функции-члены. Также нет проблем с вызовом protected функция-член базового класса из вложенной структуры, то есть следующий код компилируется и работает правильно:

#include <iostream>

class Base
{
public:
Base()
{}

protected:
void baseProtectedFunc()
{
std::cout << __func__ << "Called for Base\n";
}
};

class Derived : public Base
{
public:
explicit Derived() : Base()
{}

void accessBaseProtectedFuncFromNested()
{
Nested myNested( this );
myNested();
}

private:
struct Nested
{
explicit Nested( Derived* ptr ) : derived_( ptr )
{}

void operator()()
{
derived_->baseProtectedFunc();
}

Derived* derived_;
};
};

int main( int, char** )
{
Derived myDerived;
myDerived.accessBaseProtectedFuncFromNested();
return 0;
}

Теперь рассмотрим следующий код, который использует mpl::inherit_linearly генерировать базовые классы для производных, используя mpl::vector типов:

#include <iostream>
#include <typeinfo>

#include <boost/mpl/vector.hpp>
#include <boost/mpl/inherit.hpp>
#include <boost/mpl/inherit_linearly.hpp>
#include <boost/mpl/for_each.hpp>

template<typename T>
class Base
{
public:
Base()
{}

protected:
void baseProtectedFunc()
{
std::cout << __func__ << "Called for Base< " << typeid(T).name() << " >\n";
}
};

typedef boost::mpl::vector< long
, unsigned
, bool
, std::string
> parameter_type_list_t;

typedef boost::mpl::inherit_linearly< parameter_type_list_t
, boost::mpl::inherit< boost::mpl::_1
, Base< boost::mpl::_2 > >
>::type base_types;

class Derived : public base_types
{
public:
explicit Derived() : base_types()
{}

template<typename T>
void accessBaseProtectedFuncFromNested()
{
Nested myNested( this );

myNested.someFunc<T>();
}

private:
struct Nested
{
explicit Nested( Derived* ptr ) : derived_( ptr )
{}

template< typename T >
void someFunc()
{
Base<T>* base = static_cast<Base<T>*>( derived_ );
base->baseProtectedFunc();
}

Derived* derived_;
};
};

int main( int, char** )
{
Derived myDerived;
myDerived.accessBaseProtectedFuncFromNested<unsigned>();

return 0;
}

При использовании GCC версии 4.4.6-3 (в режиме c ++ 03 и c ++ 0x) генерируется следующая ошибка:

friend-prot.cpp: In member function ‘void Derived::Nested::someFunc() [with T = unsigned int]’:
friend-prot.cpp:47:   instantiated from ‘void Derived::accessBaseProtectedFuncFromNested() [with T = unsigned int]’
friend-prot.cpp:82:   instantiated from here
friend-prot.cpp:17: error: ‘void Base<T>::baseProtectedFunc() [with T = unsigned int]’ is protected
friend-prot.cpp:72: error: within this context

Если я делаю функцию, я пытаюсь вызвать public код компилируется и работает как положено.

Я могу обойти проблему, добавив дополнительный private функция-член для производного, которая просто перенаправляет вызов из Nested, т.е.

struct Nested
{
explicit Nested( Derived* ptr ) : derived_( ptr )
{}

template< typename T >
void operator()()
{
derived_->forwarder<T>();
}

Derived* derived_;
};template< typename T >
void forwarder()
{
Base<T>::baseProtectedFunc();
}

Я не понимаю, почему я не могу позвонить baseProtectedFunc() если это protected когда mpl::inherit используется.

Почему мне разрешено вызывать защищенную функцию базового класса в первом примере, а не во втором?

2

Решение

Вы обнаружите, что получили бы ту же ошибку, если бы вы написали функцию пересылки как

template <typename T>
void forwarder()
{
Base<T>* base = static_cast<Base<T>*>( derived_ );
base->baseProtectedFunc();
}

Проблема в том, что приведение к базовому указателю скрывает компилятору тот факт, что baseProtectedFunc фактически доступен из текущего контекста с указанным указателем. Поскольку это скрыто, компилятор должен предположить, что доступ через этот указатель не разрешен.

Поскольку синтаксис, который вы использовали в функции пересылки, также можно использовать из вложенного класса, решение довольно простое и элегантное:

struct Nested
{
explicit Nested( Derived* ptr ) : derived_( ptr )
{}

template< typename T >
void someFunc()
{
derived_->Base<T>::baseProtectedFunc(); /* <-- Changed */
}

Derived* derived_;
};
1

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

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector