Search code examples
c++includefriend

Selectively hide member of member of class


// PhysicalTraits.h
struct PhysicalTraits {
     unsigned int age; // years
     double height; // meters

     PhysicalTraits(const double H = 0.0, const unsigned int A = 0u) : age (A), height(H) {};
     ~PhysicalTraits() {};
};

// People.h
#include <PhysicalTraits.h>
class People {
    PhysicalTraits traits;

public:
    People(const double H = 0.0, const double A = 0u) : traits(H, A);
    ~People() {};

    void displayAge() { std::cout << "You are " << traits.age << " years old." << std::endl; }
    void displayHeight() { std::cout << "You are " << traits.height << " meters tall." << std::endl; }
};

// Me.h
#include <PhysicalTraits.h>
class Me {
    PhysicalTraits traits;

public:
    Me(const double H = 0.0) : traits(H);
    ~Me() {};

    void displayAge() {
        // I want `traits.age` to throw an error 
        std::cout << "You are " << traits.age << " years old." << 
    }
    void displayHeight() { 
        std::cout << "You are " << traits.height << " meters tall." << std::endl; 
    }
};

I intend to allow objects of type People to access traits.age. However, I don't want to know my age, so I want to restrict objects of type Me from accessing traits.age.

To do this, I modified PhysicalTraits.h:

#include <People.h>
struct PhysicalTraits {
    double height; // meters
private:
    unsigned int age; // years
    friend class People; // Objects of type `People` can access age
};

With age as a private member variable and as a friend with People, but not Me. I've solved the problem... kind of.

However, the new problem is that I've included People.h in PhysicalTraits.h and PhysicalTraits.h in People.h. So, when PhysicalTraits.h is compiled, before defining the PhysicalTraits object it will jump to the definition of the People object, which requires that the PhysicalTraits object is defined.

How can I avoid this "mutual-include" problem while still ensuring that an object of type Me cannot access traits.age?


Solution

  • You don't have to include People.h in PhysicalTraits.h. Full definition of class People is not required there. You can just declare that class.

    PhysicalTraits.h would look like that:

    class People;  // Forward declaration
    
    struct PhysicalTraits {
        double height; // meters
    private:
        unsigned int age; // years
        friend class People; // Objects of type `People` can access age
    };
    

    Forward declarations was created exactly in order to solve problems like yours (mutual-include). In c++ you code is (in general) parsed from top to bottom which creates a lot of problems when you need to use e.g. function which is defined after the call. Thats why declaration was implemented. In your case compiler need to know only the name of the class, so declaration will suffice. However, you cannot create object of class which is only declared or call any of its methods.

    It's also noteworthy that using declaration everywhere where it is possible speeds up the compilation because parsing a definition obviously takes some time.