#include <memory>

namespace restricted
{
    struct A
    {
        virtual ~A() {}
        virtual int value_a() const { return a ; }

        protected:
            int a = 0 ;
            virtual void value_a( int i ) { a = i ; }
    };

    struct B : A
    {
        virtual int value_b() const { return b ; }

        protected:
            int b = 0 ;
            virtual void value_b( int i ) { b = i ; }
    };
}

namespace exposed
{
    struct A : restricted::A
    {
        using restricted::A::value_a ;
    } ;

    struct B : restricted::B
    {
        using restricted::B::value_a ;
        using restricted::B::value_b ;
    } ;
}

int main()
{
    auto exposed_a = std::make_shared<exposed::A>() ;
    int v = exposed_a->value_a() ;
    exposed_a->value_a(v) ; // fine, exposed

    auto exposed_b = std::make_shared<exposed::B>() ;
    v = exposed_b->value_a() ;
    exposed_b->value_a(v) ; // fine, exposed
    v = exposed_b->value_b() ;
    exposed_b->value_b(v) ; // fine, exposed

    std::shared_ptr<restricted::A> restricted_a(exposed_a) ; // fine, exposed::A => restricted::A

    v = restricted_a->value_a() ; // fine
    // restricted_a->value_a(v) ; // *** error **** restricted::A::value_a(int) is protected

    restricted_a = exposed_b ; // also fine, exposed::B => restricted::A

    std::shared_ptr<restricted::B> restricted_b(exposed_b) ; // fine, exposed::B => restricted::B

    v = restricted_b->value_a() ; // fine
    // restricted_b->value_a(v) ; // *** error **** restricted::B::value_a(int) is protected
    v = restricted_b->value_b() ; // fine
    // restricted_b->value_b(v) ; // *** error **** restricted::B::value_b(int) is protected
}
