0

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", "alice.smith@test.com");
    user2.setUser(8, "Bob", "Jones", "bob.jones@test.com");

    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;

}
Community
  • 1
  • 1
  • 1
    This has nothing to do with the getter and everything to do with not having a `<<` overload for `User`. C++ has no idea how to write a custom class into a stream unless you teach it. Good advice on how to dio that found at [What are the basic rules and idioms for operator overloading?](https://stackoverflow.com/questions/4421706/what-are-the-basic-rules-and-idioms-for-operator-overloading) – user4581301 Mar 12 '20 at 18:46
  • On the other hand it might just be that you need to change `User getUserID() { return userID; }` into `int getUserID() { return userID.getUserID(); }`. Message only knows the `User`. It needs to ask the `User` for the `User`'s ID. – user4581301 Mar 12 '20 at 18:49
  • 1
    Unrelated The `Message` member variable `userID` has a confusing name. A user-id is an `int` according to the definition in `User`. A better name for the variable in `Message` would be `user`, since that's what it is. – Ted Lyngmo Mar 12 '20 at 18:51
  • @user4581301 - The second solution worked perfectly, thank you so much! I'd been banging my head against the wall for an hour trying to figure this out! – floorboard01 Mar 12 '20 at 18:52

2 Answers2

1

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.

user4581301
  • 33,082
  • 7
  • 33
  • 54
  • Regarding your addendum, would I substitute this for the user ID getter in my Message class? When I try this I'm getting "Message:user cannot access private member declared in class Message' – floorboard01 Mar 13 '20 at 19:56
  • @floorboard01 I'd place it in `Message`'s definition right before `getUserID`. It really doesn't matter where in `Message`'s `public` area it goes, but it's generally best to keep like with like. – user4581301 Mar 13 '20 at 20:54
0

If you just want to print the userID member of User you can't pass the whole object to std::cout because it doesn't know how to print it.

The way you can do this with the minimal amount of change in your code is to just print userID member of the User object thtrough the getter you created.

 cout << "message ID: " << msg1.getMsgID() << ", user ID: " << msg1.getUserID().getUserID() << ", message: " << msg1.getMessage() << endl;
                                                                              ^^^^^^^^^^^^^^

Live sample

Or if you want to pass the whole object to std::cout you will need to overload operator <<.

anastaciu
  • 23,467
  • 7
  • 28
  • 53