Search code examples
c++nestedfriendnested-classfriend-class

How a friend class can access a private member of a nested class?


Consider the following example:

class SIP{
    public:
        friend std::ostream& operator<<(std::ostream& os, const SIP& c);
    private:
        class BusStop;
        std::vector<BusStop*> mbusStops;
};

class SIP::BusStop{
    private:
        struct BusInfo;
        std::vector<BusInfo*> mbusStopTerminal;
};

struct SIP::BusStop::BusInfo{
    std::string from;
    std::string to;
};

std::ostream& operator<<(std::ostream &os, const SIP &c) {
    for (std::vector<SIP::BusStop*>::const_iterator it = c.mbusStops.begin(); 
         it != c.mbusStops.end(); it++){
        for (std::vector<SIP::BusStop::BusInfo*>::const_iterator it2 = mbusStopTerminal.begin(); 
             it2 != mbusStopTerminal.end(); it2++){
        }
    }
    return os;
}

It won't compile, because the BusInfo struct is private. Friend classes can't access private members of nested classes by default. What should I do in that situation? Is there any workaround?


Solution

  • You could add a stop-printing function to SIP:

    class SIP{
        public:
            friend std::ostream& operator<<(std::ostream& os, const SIP& c);
        private:
            void printStops(std::ostream& os);
            class BusStop;
            std::vector<BusStop*> mbusStops;
    };
    
    std::ostream& operator<<(std::ostream &os, const SIP &c) {
        c.printStops(os);
        return os;
    }
    

    or you could just add operators all the way down:

    class SIP{
        public:
            friend std::ostream& operator<<(std::ostream& os, const SIP& c);
        private:
            class BusStop;
            std::vector<BusStop*> mbusStops;
    };
    
    class SIP::BusStop{
        private:
            friend std::ostream& operator<<(std::ostream& os, const BusStop& c);
    
            struct BusInfo;
            std::vector<BusInfo*> mbusStopTerminal;
    };
    
    struct SIP::BusStop::BusInfo{
        std::string from;
        std::string to;
    };
    
    std::ostream& operator<<(std::ostream &os, const SIP::BusStop::BusInfo &i)
    {
       // Whatever
    }
    
    std::ostream& operator<<(std::ostream &os, const SIP::BusStop &c)
    {
        for (std::vector<SIP::BusStop::BusInfo*>::const_iterator it = mbusStopTerminal.begin(); 
             it != mbusStopTerminal.end(); it++){
            os << **it;
        }   
    }
    
    std::ostream& operator<<(std::ostream &os, const SIP &c) {
        for (std::vector<SIP::BusStop*>::const_iterator it = c.mbusStops.begin(); 
             it != c.mbusStops.end(); it++){
            os << **it;
        }
        return os;
    }
    

    or any combination of approaches that suits your code.