Помощь - Поиск - Пользователи - Календарь
Полная версия: Запись и чтение контейнеров(а именно vector)
Форум «Всё о Паскале» > Современный Паскаль и другие языки > Ада и другие языки
Andrewshkovskii
Можете привести примеры чтения и записи вектора через операторы << и >>?
я просто пока плохо представляю как это реализовать.. norespect.gif

допустим вот для этого пример :

class Team
{
public :
friend ostream& operator << (ostream& outs, const vector<Team>&);
friend istream& operator >> (istream& sin, vector<Team>&);
friend void file_save(const vector<Team>&);
private:

string TeamName;
int win;
int lose;
int draw;
int score;

};




ostream&  operator << (ostream& outs, const vector<Team>& v) 
{
outs << "Team " << " Wins " << "Loses " << "Draws " << "Scores\n";
for (unsigned int i=0;i<v.size();i++)
{

outs << v[i].TeamName;
set_spaces_t(v,i);
outs << v[i].win << " " << v[i].lose << " " << v[i].draw << " " << v[i].score << "\n";

}

return outs;
}


Как надо правильно переопределить оператор >> для чтения из файла?.
вот функция записи допустим
:
void file_save(const vector<Team>& v){
char filename[15];
cout <<"Enter a file name(without extension) : ";
cin >> filename;
//filename=filename+".sys";
ofstream outfile(filename);
outfile << v;
}



Извиняюсь,Если как-то плохо объяснил что нужно,или наплел тут чуши - голова уже не варит к концу дня.
volvo
А зачем, собственно, тебе перегружать операцию ввода/вывода именно для вектора? Это чем-то обосновано? Почему не перегрузить именно для класса, и не читать/добавлять в вектор, пока не достигнем конца файла?

Кстати, пример файла, из которого читаются данные, можно привести?
Andrewshkovskii
ну как видно по коду,он так же будет создан не правильно,ибо туда вводиться все то,что выводит оператор << для класса Team.
Это грубо не правильно,и я это понимаю.Я только решил попробывать.Хм..тоесть ,читать объект,потом делать push_back к этому объекту?в цикле читать..хм..просто я хотел написать метод,который бы читал сразу весь вектор..
volvo
Ну, так напиши себе метод (скажем, такой:

class Team {
public:
file_read(ifstream& fin, vector<Team>& vt);
...
};

), который будет читать поэлементно и делать push_back в вектор. А перегрузку >> делай именно для Team...
Andrewshkovskii
хм..сейчас попробую.Кстате,вопрос такой : почему дружественные функции не нарушают принципы инкапсуляции?
Ещё один : почему нельзя для outfile передавать имя файла как string?только чар?а если я хочу что бы пользователь не задавал расширение файла,мне же проще будет написать так :

string filename;
cout <<"Enter a file name(without extension) : ";
cin >> filename;
filename=filename+".sys";
ofstream outfile(filename);

безусловно,в чар-строку можно тоже добавить символы.Просто так же проще,вроде..?
volvo
Потому, что дружественная функция - это часть интерфейса класса, определяемая разработчиком, а не пользователем, а значит, при правильном использовании дружественных функций, никто ИЗВНЕ доступа туда, куда не надо не получит...

Цитата
почему нельзя для outfile передавать имя файла как string?только чар?а если я хочу что бы пользователь не задавал расширение файла,мне же проще будет написать так :
Собственно, кто мешает:

string filename;
cout <<"Enter a file name(without extension) : ";
cin >> filename;
filename=filename+".sys";
ofstream outfile(filename.c_str(), ios::out);

?
Andrewshkovskii
хм..спасибо=)
Написал тут кое-что..только почему-то не хочеть работать..

вот функция сохранения в файл :

void file_save(const vector<Team>& v){
char filename[15];
cout <<"Enter a file name(without extension) : ";
cin >> filename;
//filename=filename+".sys";
ofstream outfile(filename);
for (unsigned int i=0;i<v.size();i++)
outfile << v[i].TeamName <<v[i].win <<v[i].lose << v[i].draw << v[i].score; ;
}


Чтения :
void file_read (vector<Team>& v)
{
Team temp_obj;
char filename[15];
cout << "Input file name : ";
cin >> filename;
ifstream infile(filename);
for (unsigned int i=0;i<v.size();i++)
{
infile >> temp_obj.TeamName >> temp_obj.win >> temp_obj.lose >> temp_obj.draw >> temp_obj.score;
//cout << " here!" << temp_obj.TeamName;
v.push_back(temp_obj);
}

}

Но вектор пуст.Почему?..
volvo
Цитата
Но вектор пуст.Почему?..
Сам не догадываешься? Чему равен размер вектора при начале операции чтения из файла? 0... А ты поставил условие i < v.size(), которое сразу же НЕ выполняется...

Читать из файла надо, пока ФАЙЛ не закончится, а не зависеть от размера вектора...
Andrewshkovskii
Спасибо и в этот раз...надо всетаки нормально в Лафоре прочитать про потоки и файлы..

Добавлено через 13 мин.
бжж..опять..


Функции :

void file_save(const vector<Team>& v){
string filename;
cout <<"Enter a file name(without extension) : ";
cin >> filename;
filename=filename+".sys";
ofstream outfile(filename.c_str(), ios::out);
for (unsigned int i=0;i<v.size();i++)
outfile << v[i].TeamName <<v[i].win <<v[i].lose << v[i].draw << v[i].score; ;
}

void file_read (vector<Team>& v)
{
Team temp_obj;
string filename;
cout << "Input file name : ";
cin >> filename;
filename=filename+".sys";
ifstream infile(filename.c_str());
while (!infile.eof()&& infile.good())
{
infile >> temp_obj.TeamName >> temp_obj.win >> temp_obj.lose >> temp_obj.draw >> temp_obj.score;
cout <<temp_obj.TeamName;
v.push_back(temp_obj);
}

}


В принципе,записываются данные в файл нормально.
А читаются..видимо в один string(TeamName) заноситься сразу вся информация из файла..как этого избежать?.
volvo
Я ж тебя просил привести пример файла, из которого читаешь информацию... Или показывай, как заполняешь вектор данными, чтобы можно было проверить именно на том файле, который записывается через file_save()...
Andrewshkovskii
содержимое файла :

team11236team21236


Как заполняю вектор?а разве в file_read не написано?или я вопрос не понял ?
:



while (!infile.eof()&& infile.good())
{
infile >> temp_obj.TeamName >> temp_obj.win >> temp_obj.lose >> temp_obj.draw >> temp_obj.score;
cout <<temp_obj.TeamName;
v.push_back(temp_obj);
}
volvo
Нет, так не пойдет... Надо разделять данные... Хотя бы пробелами smile.gif

Смотри:

team.h
#ifndef TEAM_H_
#define TEAM_H_

#include <iostream>
#include <string>
#include <vector>

using namespace std;

class Team
{
friend ostream& operator << (ostream&, const Team& );
friend istream& operator >> (istream&, Team& );
public:
string TeamName;
int win;
int lose;
int draw;
int score;

Team ();
};

// Это - НЕ метод класса, не нужно инициализировать лишний объект,
// чтобы через него вызывать эту функцию.

void file_read(vector<Team>&);

#endif /*TEAM_H_*/




main.cpp
...

ostream& operator << (ostream& os, const Team& ob)
{
os << ob.TeamName << " " << ob.win << " " << ob.lose <<
" " << ob.draw << " " << ob.score;
return os;
}

istream& operator >> (istream& is, Team& ob)
{
int ch; // <--- Добавлено

getline(is, ob.TeamName, ' ');
is >> ob.win >> ob.lose >> ob.draw >> ob.score;

while(is && (ch = is.get()) != '\n'); // <--- Добавлено
return is;
}

void file_read(vector<Team>& vt) {

// Хотя вот это я бы сделал ДО вызова file_read(), и передавал
// бы сюда уже именно открытый поток ввода, как и показал выше

string filename;
cout <<"Enter a file name(without extension) : ";
cin >> filename;
filename = filename + ".txt";

ifstream infile(filename.c_str(), ios::in);
Team t;
while(infile >> t) {
vt.push_back(t);
}
infile.close();
}

vector<Team> vt;
int main() {

file_read(vt); // Читаем

// Проверяем
for(vector<Team>::iterator it = vt.begin(); it != vt.end(); it++) {
cout << *it << endl;
}
return 0;
}

Вот так...
Andrewshkovskii
Спасибо за помощь!Но всеравно не много не понимаю пока..ну разберусь.У меня теперь новый вопросsmile.gif
Допустим,имеется какой-то класс с полями int и string.И есть вектор этих объектов v.
Я хочу отсортировать вектор с помощью алгоритма sort() по заданным параметрам,т.е сортировка по i (в порядке возрастания,или убывания), сортировка по str (так же,в порядке возрастания и убывания).Понятно,что для этих типов определен оператор < и оператор >. Но,если я просто вызову функция sort(v.begin(),v.end()); ,то будет ошибка.Так вот, надо ли мне,определять предикат сортировки для каждого из параметров?

Допустим вот так :

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;

class c{
public :
int c;
string str;
};



bool sortbystr(const c& first,const c& second)
{
return (first.str==second.str);
}

int main() {
vector<c> v;
sort(v.begin(),v.end(),sortbystr);
return 0;
}


Будет ли это правильно?

2ой вопрос : допустим,имеется клас Team

class Team
{
public :

string TeamName;

};


и класс Player :

class Player
{
public :
long int salary;
string Lname;
string team;

};



Необходимо,что бы при вводе поля team, происходила проверка : имеется ли данная команда в векторе класса Team.Т.е.,вводим ли мы реально существующую команду,к которой принадлежит игрок или нет.
С помощью какого алгоритма stl можно сделать данную проверку?find,search или же проще и лучше написать самому(это то я понимаю как написать,но хочется освоить stl алгоритмы)?Если можно,приведите,пожалуйста,пример.
volvo
Цитата
надо ли мне,определять предикат сортировки для каждого из параметров?
Да, если ты хочешь иметь возможность сортировать вектор по нескольким разным полям...

Цитата
С помощью какого алгоритма stl можно сделать данную проверку?find,search или же проще и лучше написать самому
Гораздо проще будет написать самому...

Update
Хотя... Я тут посмотрел на то, что сделал вчера - есть небольшое добавление, я внес исправления в пост №12, в реализацию operator >> для класса Team. С учетом этого, можно сделать и с помощью алгоритма find_if:

1. Описываем в классе Team константный метод
class Team {
...
string get_team_name() const {
return TeamName;
}
}

2. Описываем также еще одну структуру:
struct check
{
string st;
bool operator() (const Team& t) const {
return (t.get_team_name() == st);
}

check(string s): st(s) {
}
};


3. И теперь проверка делается так:

    ...
vector<Team> vt;

string team; // наличие этой строки в vt будем проверять
cin >> team;

vector<Team>::iterator found;
found = find_if(vt.begin(), vt.end(), check(team)); // Собственно, поиск

// Проверяем, нашлось что-то или нет:
if(found != vt.end()) {
cout << "найдено: " << *found << endl;
}
else {
cout << "не найдено" << endl;
}
...
Andrewshkovskii
Ну я отсутствовал в инете пару дней..когда ты сказал проще самому написать,я написал..Только почему-то циклиться,а почему - не пойму.Возможно гдето-то с параметрами напутал..вот такая картина :

void input_p (vector<Player>& v,const vector<Team>& vt)
{
cout <<"Input number of Player's to add : ";
int j;
cin >> j;
Player ob;
for (int k=0;k<j;k++)
AddOne_p(v,ob,vt);
}

void AddOne_p (vector <Player>& v,Player ob, const vector<Team>& vt)
{
cout <<"Input Player last name : ";
cin >> ob.Lname;
cout <<"\nInput team name, in which Player play : ";

while(exsist_c(ob.club,vt))
cin >> ob.club;
cout << "\nInput Player salary : ";
cin >> ob.salary;
v.push_back(ob);
}

bool exsist_c (string& club ,const vector<Team>& vt ) {
bool ye=0;
for (unsigned int i=0;i<vt.size();i++)
{
if(club==vt[i].TeamName)
ye=1;
else
{
cout <<"Entered team does not exsist";
ye=0;
}
}
return ye;
}


вроде подправил,надо было поток очистить..
пипеец..и функция вызывал ДО ввода команды..идиот..проститеsmile.gif
volvo
Насколько я вижу - вот так будет лучше:

bool exsist_c (string& club, const vector<Team>& vt ) {

for(unsigned int i = 0; i < vt.size(); i++) {
if(club == vt[i].TeamName) return 1;
}
cout <<"Entered team does not exsist"; // Это можно делать только после просмотра всего вектора
return 0;

}
Это первое... Второе - вопрос на засыпку: зачем ты передаешь ob в AddOne_p()? Можно же не тянуть его извне, а описывать прямо внутри этой функции, ты ж все равно не пользуешься (да и не сможешь, передается-то объект не по ссылке, а по значению) введенными данными в самой функции input_p()...
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.