Search code examples
c++classprivate

C++ Accessing a private member of a class from another class using getters


I'm trying to define two classes, one for users and one for messages. The Message class will have an attribute UserID to identify who posted the message, which is also an attribute of the User class.

I've followed a tutorial which did this for a restaurant (with Users, Foods, and an Orders class made up of attributes from Users and Foods) but the attributes were all set to public and my assignment has asked me to do this with private attributes with getters / setters. At the end I have a cout statement which prints attributes from the Message class, but the attribute that is also part of the User class is generating the following errors:

Error C2679 binary '<<': no operator found which takes a right-hand operand of type 'User' (or there is no acceptable conversion)

Error (active) E0349 no operator "<<" matches these operands

If I remove the msg.getUserID part of the Cout statement, the code runs OK.

The other instances of this question I've found were related to public attributes, or used the Friend keyword. Is there any other way of doing this? I've tried moving the attribute to public in the User class (though I can't do this for my assignment) but I still get the same errors. I assume it's because I've declared getUserID in the Message class as type User but I can't find another way of doing this. I'm very new to C++ so apologies if some of the code is not the most efficient way to do something (this is a mandatory module on my analytics course, I've only used Python up to this point). Any help would be really appreciated. Thanks!

#include <iostream>
#include <string>

using namespace std;


class User {
private:
    int userID;
    string firstName;
    string lastName;
    string email;

public:
    void setUser(int userID, string firstName, string lastName, string email) {
        this->userID = userID;
        this->firstName = firstName;
        this->lastName = lastName;
        this->email = email;
    }

    int getUserID() {
        return userID;
    }

    string getFirstName() {
        return firstName;
    }

    string getLastName() {
        return lastName;
    }


    string getEmail() {
        return email;
    }

};


class Message {
private:
    int msgID;
    User userID;
    string message;

public:
    void setMessage(string message, User userID) {
        static int msgID = 0;
            msgID++;
        this->message = message;
        this->msgID = msgID;
        this->userID = userID;
    }

     string getMessage() {
         return message;
     }

     User getUserID() {
         return userID;
     }


     int getMsgID() {
         return msgID;
     }

};

int main()
{
    User user1;
    User user2;
    
    user1.setUser(5, "Alice", "Smith", "[email protected]");
    user2.setUser(8, "Bob", "Jones", "[email protected]");

    Message msg1;
    Message msg2;

    msg1.setMessage("Hello this is a message", user1);
    msg2.setMessage("this is a second message", user2);
    cout << "message ID: " << msg1.getMsgID() << ", user ID: " << msg1.getUserID() << ", message: " << msg1.getMessage() << endl;
    cout << "message ID: " << msg2.getMsgID() << ", user ID: " << msg2.getUserID() << ", message: " << msg2.getMessage() << endl;

}

Solution

  • Message only knows the User named userID. It needs to ask the User for the User's ID, so change Message's

    User getUserID() { // side note: This function returns a copy of userID
        return userID;
    }
    

    into

    int getUserID() {
         return userID.getUserID();
    } 
    

    Which returns a user ID rather than a User. A function name should always describe what a function does.

    And strongly consider changing User userID; into something less prone to causing confusion. Like a function, a variable's name should describe what the variable represents.

    Addendum

    If you find yourself needing a function to return Message's contained User, consider

    const User & getuser() const
    {
        return userID;
    }
    

    This returns the User by reference and avoids copying the User. The first const means the User returned from this function cannot be (easily) changed. The second const means that calling this method will not change the Message. Always default to const until forced to change. This can prevent a lot of runtime bugs by catching them at compile-time.