C++ Access private member of nested class

2019-07-04 05:29发布

问题:

The title might be a bit misleading. I have the following problem: I have a tree consisting of leaves and internal nodes. The user should be able to store any information in the leaves and the tree has some methods which get a set of user-defined values and need to access the corresponding leaves in constant time (not amortized).

I came up with the following idea but it does not work because unfortunately I cannot access private members of a nested class: The user creates the tree and also for each leaf an instance of UserElement which contains the user_defined value for the corresponding leaf. Once a method like doSomethingWithTheTree(list>) is called and the tree is built, the tree creates the corresponding leaves and saves it in the private field leaf. Whenever the user wants to call a method with some of the leaves corresponding to its user_defined values, he/she just has to call the method by giving the corresponding UserElements and the tree can retrieve the corresponding leaves in constant time.

class Tree {
    public:
        template <typename T>
        class UserElement {
            private:
                T user_value;
                tree_node* leaf; // this has to be private for
                                 // everyone outside the class `Tree`
            public:
                T getInf() {
                    return user_value;
                }
                void setInf(T i) {
                    user_value = i;
                }
        };

        void doSomethingWithTheTree(list<UserElement<T>> elements) {
            ...
            // I want to be able to access elem.leaf for all elements
        }
}

回答1:

Technically, that's a nested class (declared within another class), not a subclass (which inherits from its superclass).

You can allow the Tree class to access its privates by making it a friend:

class UserElement {
    friend class Tree;
    // ...
};

or, for better encapsulation, you could restrict access only to the member function(s) that need it, although it gets a bit messy due to the need to declare things in the right order:

class Tree {
public:
    // Declare this so we can declare the function
    template <typename T> class UserElement;

    // Declare this before defining `UserElement` so we can use it
    // in the friend declaration
    template <typename T>
    void doSomethingWithTheTree(list<UserElement<T>> elements) {
        elements.front().leaf;
    }

    template <typename T>
    class UserElement {
        // Finally, we can declare it a friend.
        friend void Tree::doSomethingWithTheTree<T>(list<UserElement<T>>);
        // ...
    };
};


回答2:

You may do

class Outer {
   private: // maybe protected:
   class Inner {
      public:
      ....
   };
};

or

class Outer {
   public:
   class Inner {
      friend class Outer;
      private:
      ....
   };
};


回答3:

You can declare class Tree a friend to UserElement<>, which would allow Tree to access all members of UserElement<>.