2

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、コードを呼び出そうとしてコンパイルされ、期待どおりに機能します。

privateNestedからの呼び出しを転送するだけの派生メンバー関数を追加することで、この問題を回避できます。

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()いるのになぜ電話できないのかわかりません。protectedmpl::inherit

最初の例では基本クラスの保護された関数を呼び出すことができ、2番目の例では呼び出せないのはなぜですか?

4

1 に答える 1

1

転送関数を次のように記述した場合、同じエラーが発生することがわかります。

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_;
};
于 2012-11-29T12:38:59.723 に答える