class user
{
private:
std::string first_name;
std::string middle_name;
std::string last_name;
int ID;
static int next_id;
public:
static int next_user_id()
{
next_id++;
return next_id;
}
group User_Group;
void set_ID(int c)
{
ID=c;
}
int get_ID()
{
return ID;
}
void set_first_name(std::string c)
{
first_name=c;
}
string get_first_name()
{
return first_name;
}
void set_middle_name(std::string c)
{
middle_name=c;
}
string get_middle_name()
{
return middle_name;
}
void set_last_name(std::string c)
{
last_name=c;
}
string get_last_name()
{
return last_name;
}
user()
{
ID = user::next_id++;
}
friend istream operator>>(istream is, user User);
friend ostream operator<<(ostream os, user User);
};
int user::next_id;
istream operator>>(istream is, user User)
{
is >> User.get_first_name();
is >> User.get_middle_name();
is >> User.get_last_name();
is >> User.get_ID();
is >> User.User_Group.get_name();
for(int j=0;j<=4;j++)
{
is >> User.User_Group.Week_Food[j].get_breakfsat();
is >> User.User_Group.Week_Food[j].get_lunch();
is >> User.User_Group.Week_Food[j].get_dinner();
}
for (int j=0;j<=30;j++)
{
is >> User.User_Group.Month_Food[j].get_breakfsat();
is >> User.User_Group.Month_Food[j].get_lunch();
is >> User.User_Group.Month_Food[j].get_dinner();
}
}ostream operator<<(ostream os, user User)
{
os<<User.get_first_name()<<" "<< User.get_middle_name() <<" "<<User.get_last_name()<<" ";
for(int j=0;j<=4;j++)
{
os<<User.User_Group.Week_Food[j].get_breakfsat()<<" "<<User.User_Group.Week_Food[j].get_lunch()<<" "<< User.User_Group.Week_Food[j].get_dinner()<<" ";
}
for (int j=0;j<=30;j++)
{
os<< User.User_Group.Month_Food[j].get_breakfsat()<<" "<<User.User_Group.Month_Food[j].get_lunch()<<" "<<User.User_Group.Month_Food[j].get_dinner();
}
}
Я новичок в C ++ и, возможно, это глупый вопрос, но мне нужно записать массив объектов в файл и прочитать его там, перегружая << и >> операторы. Я получаю сообщение об ошибке, когда пытаюсь использовать его для членов класса int и bool. Кажется, он работает нормально для строковых типов, поэтому я не знаю, как действовать дальше.
Одна из проблем здесь:
is >> User.get_ID();
get_ID()
возвращает int
по значению. Для того, чтобы «поток» значение в ID
переменная, вам нужно будет вернуть (неконстантную) ссылку на нее:
class user {
....
int& get_ID() { return ID; } // non-const version (e.g. for istream)
const int& get_ID() { return ID; } // const version
...
};
Кроме того, вам нужно, чтобы операторы брали и возвращали ссылки на потоки:
friend istream& operator>>(istream& is, user User);
friend ostream& operator<<(ostream& os, user User);
Вы также можете избежать копирования User
объекты, передавая ссылки:
friend istream& operator>>(istream& is, user& User); // modifies user so no const
friend ostream& operator<<(ostream& os, const user& User); // should not modify user
Это потребует, чтобы вы сделали ваши методы получения const
, что вы должны сделать в любом случае.
В вашей функции чтения у вас есть такие строки:
is >> User.get_first_name();
is >> User.get_middle_name();
is >> User.get_last_name();
is >> User.get_ID();
Эти функции возвращают lvalues или значения, которые могут быть читать из не то, что может быть написано. Вы мог добавьте перегрузки этих функций следующим образом:
int & get_ID() // Note return of reference to member variable!
{
return ID;
}
Но тогда вам придётся сделать методы получения, которые у вас есть, const (которые вы должны делать в любом случае, потому что они запрашивают объект, а не изменяют его):
int get_ID() const // <- note const - meaning this fn doesn't change user.
{
return ID;
}
Это связано с тем, что перегрузки нельзя отличить только по типу возвращаемого значения. заставляя получателей const сделать неявным этот аргумент const&,
Сказав все это, я бы НЕ добавить перегрузки, которые возвращают ссылки. Это плохая практика, так как она выставляет переменные-члены потенциально разрушительным образом.
Я рекомендую читать из istream в локальные переменные, а затем использовать ваши сеттеры. Вот для чего они здесь.
int myID;
is >> myID;
set_ID(myID);
Это открывает возможность того, что:
Ваши сеттеры могут проверять входные данные, которые закорочены, читая непосредственно в ваш объект класса.
Вы можете добавить проверку, что не было ошибки после чтения из входного потока.
Это дает вам гибкость. Я обнаружил, что всегда лучше защитить себя от искаженных файлов и баз данных.
Причина, по которой код не компилируется, состоит в том, что вы читаете во временный файл, который компилятор не позволяет вам. Дело в том, что призыв к get_ID()
возвращает копия(!) значения в структуре пользователя. Если вы затем сохраните какое-то значение в этой копии, оригинал останется неизменным в любом случае. Помните, что по умолчанию все параметры, передаваемые в функции и возвращаемые из функций, копируются.
Чтобы исправить это, вместо использования is >> User.get_ID()
использование is >> User.ID
, Я бы сделал это аналогично для вывода, но там это не имеет значения. Вы можете получить доступ к этим частным переменным, потому что operator>>
а также operator<<
являются функциями друга.