Jalfor
Jalfor

Reputation: 103

C++: Allowing Access to Protected Members of Class and not Private Members

I know you can do this with inheritance, but you're meant to use inheritance for except for 'is a' circumstances. I also know there are friends, but they allow access to private members as well.

Is there any way of doing this (Allowing Access to Protected Members of Class and not Private Members)?

To reword the question, I have class 1 and class 2. I want class two to have access to class 1's protected and public members, but not it's private members. How would I do this?

Upvotes: 4

Views: 2041

Answers (3)

Matthieu M.
Matthieu M.

Reputation: 300239

Long ago, on this very website, I presented a scheme using a Key. The idea is that the main class documents which parts of the interface are accessible publicly and which necessitates a key, and then friendship to the key is granted to those who need it.

class Key { friend class Stranger; Key() {} ~Key() {} };

class Item {
public:
    void everyone();

    void restricted(Key);
private:
};

Now, only Stranger may use the restricted method, as is demonstrated here:

class Stranger {
public:
    void test(Item& i) {
        Key k;
        i.restricted(k);
    }

    Key key() { return Key(); }

    Key _key;
};

class Other {
    void test(Item& i) {
        Stranger s;
        i.restricted(s.key()); // error: ‘Key::~Key()’ is private
                               // error: within this context
    }

    void test2(Item& i) {
        Stranger s;
        i.restricted(s._key); // error: ‘Key::~Key()’ is private
                              // error: within this context
                              // error:   initializing argument 1 of ‘void Item::restricted(Key)’
    }
};

It is a very simple scheme which allows a much finer grained approach that full friendship.

Upvotes: 2

justin
justin

Reputation: 104708

Oli's provided a closer solution (+1), but you could also approach it using a selective friend:

#include <iostream>

class t_thing;

class t_elsewhere {
public:
    void print(const t_thing& thing);
};

class t_thing {
public:
    class t_selective_friend {
        static int Prot(const t_thing& thing) {
            return thing.prot;
        }

        friend class t_elsewhere;
    };
public:
    int publ;
protected:
    int prot;
protected:
    int priv;
};

void t_elsewhere::print(const t_thing& thing) {
    std::cout << t_thing::t_selective_friend::Prot(thing) << std::endl;
}

int main() {
    t_thing thing;

    thing.publ; /* << ok */
    thing.prot; /* << error */
    thing.priv; /* << error */
    t_elsewhere().print(thing); /* << ok */
    return 0;
}

Sometimes that verbosity/control is good…

Upvotes: 1

Oliver Charlesworth
Oliver Charlesworth

Reputation: 272687

It's not elegant, but this might work for you:

class B;

class A {
protected:
    int x;
private:
    int y;
};

class A_wrapper : public A {
    friend B;
};


class B {
public:
    A_wrapper a;
    int foo() {
        a.x;   // Ok
        a.y;   // Compiler error!
    }
};

Upvotes: 5

Related Questions