Who has access to your private parts?

17 12 2011

A famous quip says that C++ is the language in which friends have access to your private parts.

But is it only friends?

When writing an RAII object I was feeling a bit lazy (which as we know is a virtue) and was surprised to discover that a local class (a class defined in a function body) has access to its enclosing class’s private members.

class outer {
    int private_;
public:
    outer() : private_(0) {}

    void print() {   cout << private_ << endl; }

    void foo()
    {
        class local { // RAII object
            outer* outer_;
        public:
            local(outer* p)
                : outer_(p)
            {
                outer_->private_++;
            }

            ~local() { outer_->private_--; }
        };

        print(); // -> 0

        {// Scope for RAII object 

            local in(this);
            print(); // -> 1
        }

        print(); // -> 0
    }
};

A quick look through the standard didn’t show where such behaviour is specified but it compiled with all the compilers I threw it at[1].

When I revealed this discovery to my cow-orkers they responded with an empathic “DUH!”  Oh well there  goes my C++ geek-cred  :o(

Allowing local classes access to private members makes a lot of sense on the language design front, after all if you can create a class in a method you should be able to do anything the method can do.  I just never thought of it before and apparently I’m not the only one.  When looking at C++11’s standard (well the final draft actually) I found the following in section 11 (Member access control):

A member of a class can also access all the names to which the class has access. A local class of a member function may access the same names that the member function itself may access.

Since this sentence does not appear in the original ’98 standard I can only assume that greater minds than mine had also missed this point, at least at first.

Having classes which can access your private parts can be very useful, they can be used for temporarily changing state (as in the RAII class above) or they can be used as parameters to STL algorithms[2]. The problem is that having a local class breaks the flow of the function and a nested class must be defined in the header so that something which is an implementation detail becomes globally visible.

But wait, the section in the standard had a footnote. “Access permissions are thus transitive and cumulative to nested and local classes.”

Transitive, that implies more than one level, this gave me an idea for a new(?) C++ pattern. I don’t know if I’m the first who thought of it and I doubt it’s very useful but here goes, I’m very proud to introduce the nested2 pattern.

For every class we can create a backdoor class that allows creation of quasi-friend classes. Then if the need arises we can add these quasi-friend classes in the .cpp file.

// .h file
class troy {
    class wooden_horse;
    int private_;
public:
    troy();
    void foo();
};

// .cpp file
class troy::wooden_horse {
public:
    struct odysseus {
        troy* t_;
        odysseus(troy* p) : t_(p)
        {
            t_->private_++;
        }

        ~odysseus()
        {
            t_->private_--;
        }
    };

    // Add Greek warriors as needed
};

troy::troy()
    : private_(41)
{
}

void troy::foo()
{
    wooden_horse::odysseus odysseus(this);
    cout << private_ << endl;
}

By making the backdoor class private we can be sure that the quasi-friend classes won’t be abused since nobody but our class will be able to create an object of this type.


Edit: Ever since I posted this I couldn’t sleep at night, I knew I would never forgive myself if I don’t to this:

:%s/troy/french_castle/g
:%s/wooden_horse/large_wooden_badger/g
:%s/odysseus/bedemir/g
:%s/Greek warriors/Knights of the round table/g
:wq

[1] VC8, VC10, gcc, clang and Comeu (yes I am a bit obsessive, why do you ask?) 

[2] Although this is less compelling since the introduction of lambda expressions in C++11. On second thought, since lambda functions are implemented as unnameable classes perhaps this is the reason for the change in the standard, to allow lambda functions the same access rights as the method that defined them. 

Advertisements

Actions

Information

4 responses

12 01 2012
knell

That’s cool but could you provide any real-life example of usage?

12 01 2012
Motti Lanzkron

@knell, the example in the post of creating an RAII object for changing state in the nesting object can be useful.

Another use can be a sort of poor man’s PImpl idiom. Say you see that several of your methods use the same logic and want to refactor the code into a separate method, if you use a nested class you can create this method without changing the deceleration of the class (thus not forcing a re-compile for all files that include your header).

31 10 2012
Krzysiek

@Motti: the “poor man’s Pimpl” is better done as non-member functions in unnamed namespace defined in class’ .cpp file. In fact it is also one of (AFAIK) Herbs’ suggestions to prefer non-member functions to member functions.

31 10 2012
Motti Lanzkron

@Krzysiek, if you have non-member functions in the class’s .cpp file you only have access to public members of the class.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: