Hello,

I have a chain of inherited classes like this:

class A
{
    protected:
    int a;
    public:
    int getA(){return a;}
};
class B:public A
{
    protected:
    int b;
    public:
    int getB(){return b;}
};

Based on that you can see that the public can only read the values in those classes, they cannot write them. However I would like to make a sort of overriding class that will allow those with access to it to modify the classes, like so:

class ExposedA:public A
{
    public:
    ExposedA &setA(int a){this->a=a;return *this;}
};
//here is where I am lost
class ExposedB:public B
{
    public:
    ExposedB &setB(int b){this->b=b;return *this;}
};

I would like to be able to also modify the a part of B, just as if I swapped ExposedA into the B class's inheritance instead of A. I could of course just inherit ExposedB from ExposedA, however I would like to be able to cast my ExposedB pointers to B pointers so that I could send them out in their unmodifyable state. Is this at all possible? (I looked into virtual access specifiers, they got me a bit confused but it seems like they could help?)

Basically this is my goal:

ExposedB *eb;
eb->setB(1)->setA(2);
B *safeB=(B*)eb;
int a=safeB->getA();
int b=safeB->getB();
//I want the following two lines to fail:
safeB->setA(1);
safeB->setB(2);

Recommended Answers

All 7 Replies

I don't see any reason for the ExposedA and ExposedB classes to enter the inheritance scheme at all. And also, from your simple example, I don't see any reason for B to inherit from A, but I assume that in your real this is needed.

Anyhow, the point is that ExposedA and ExposedB classes should probably just be wrappers of A and B objects. To get access to their protected / private parts, you would just need to have them either as friend classes or as nested classes. I tend to prefer the nested classes, as so:

class A
{
  protected:
    int a;

  public:
    int getA() const { 
      return a;
    }

    // nested accessor class:
    class exposed {
      protected:
        A* p_a;

      public:
        explicit exposed(A& aRA) : p_a(&aRA) { };

        const exposed& setA(int aA) const { p_a->a = aA; return *this; }
    };
};

class B : public A
{
  protected:
    int b;

  public:
    int getB() const { 
      return b;
    };

    // nested accessor class:
    class exposed : public A::exposed {
      public:
        explicit exposed(B& aRB) : A::exposed(aRB) { };

        const exposed& setB(int aB) const { static_cast<B*>(p_a)->b = aB; return *this; }
    };
};

Meaning that the main function looks like this:

int main() {
  B b_obj;
  B::exposed(b_obj).setB(1).setA(2);
  int a = b_obj.getA();
  int b = b_obj.getB();
  //I want the following two lines to fail:
  b_obj.setA(1);
  b_obj.setB(2);
};

So, this is really the simplest solution because it really does the only thing that you really need, which is to be able to explicitly make the object's internal accessible, temporarily, for where you need to manipulate them. Ideally, you should not need this at all, but if you do, you must limit it to a temporary and explicit wrapper.

Canonical:

#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
}

http://ideone.com/k0cA1O

I tend to prefer Mikael's version a bit better, it seems less 'hack-y'. I actually had it implemented like that before, with a processor class that was a friend to all the other classes. I suppose I will be doing the same thing again. (I like friends a bit more than wrappers just because I find it easier to spread my code out that way). Thank you both though.

Oops, I forgot to ask one quick thing. Does friendship get inherited? If I have a 'most base' class. Could I put friend class ClassExposer; in it and have it carry to each object that inherits it. Or do I have to put it in each subsequent class?

Friends are not inherited. Usually if you are a friend class and you want your derived classes to have access to the friending class' private and protected members, then you will need to add the appropriate functions to access them in yourself (the friend class). Example:

class AnotherClass;
class SomeClass {
private:
    int m_int;
public:
    SomeClass(int value = 0) : m_int(value) {}

    friend class AnotherClass;
};

class AnotherClass {
public:
    AnotherClass() {}
    int getSomeInt(const SomeClass& sc) const { return sc.m_int; }
    void setSomeInt(SomeClass& sc, int value) { sc.m_int = value; }
};

So, AnotherClass has just made the m_int property of SomeClass instances publically available. If you want to restrict that access to just derived classes, then make those access functions protected.

Actually what I will do is have the definition of AnotherClass in a secured header. That way I can check to see if it has been included, and if it has I know there is a problem. My issue is that I have a long chain of inherited classes (my java friends like every single insignificant "is-a" relationship to be inherited :( ) and I didn't want to have to write a friend line for each one. However, I suppose I will have to. Thanks.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.