| Другое > Hard'n'Soft |
| Програмирование на C++ |
| << < (7/25) > >> |
| HoRRoR:
Э, а ничего, что у тебя прототип не соответствует функции? Т.е. это описания двух разных функций. Либо приведи их к общему виду, либо перенеси функцию выше мэйна и не используй прототип. |
| gepar:
Отложу немножко указатели, чтобы потом к ним вернуться, так как у меня тут появилось "чудное" задание: переделать лабы на структуры, но с использованием классов и структур одновременно (это если я всё правильно понял), собственно возник вопрос: если я запихну структуру в класс, то как я из main напрямую для конкретного созданного мной класса потом к ней смогу обратиться? Получается никак чтоли и мне нужно делать целую кучу set и get функций для каждой строчки структуры для того чтобы работать с той структурой в классе? :( |
| HoRRoR:
Зачем? Возвращай через get ссылку или указатель на структуру и делов-то. |
| gepar:
Я тебья не панимать патаму шта я изучать с++, но не знать его полнастью :) Я пока возвращал указатели только с целью построения каскадного вызова функции, учитывая что я get с ходу применить не могу (надо бы для начала добавить элемент через set в структуру же чтобы к нему обращаться) то мне получается надо сделать кучу set функций ну и вообще получив указатель на элемент структуры я ведь не смогу узнать адрес сл. элемента так как в структуре элементы же строки... или я опять что-то не так понял. Вот мой пример по структурам что надо пихнуть в класс теперь (динамические пока не трогаю, на обычных думаю понять тебя проще будет): --- Код: ---//Программа создаёт структру, запрашивает данные для её заполнения после //чего производит поиск по структуре введённых данных # include <iostream> # include <iomanip> # include <windows.h> using namespace std; const int size=3; struct PRICE { char name[30];// название товара char shop[30];//;// название магазина double cost;// цена товара }abc[size]; int main() { SetConsoleCP(1251); SetConsoleOutputCP(1251); char search[30]; int result=0; for (int i=0;i<size;i++) { cout<<"Введите название товара: "; cin>>abc[i].name; cout<<"Введите название магазина: "; cin>>abc[i].shop; cout<<"Введите цену товара в грн: "; cin>>abc[i].cost; cout<<endl; } cout<<"Введите имя интересущего вас товара: "; cin>>search; for (int j=0;j<size;j++) { if (!(strcmp(search,abc[j].name))) { cout<<"Нужный вам товар есть в магазине "<<abc[j].shop <<"\nЕго цена составляет: "<<abc[j].cost<<" грн"<<"\n\n"; result=1; }; }; if (result==0) cout<<"Указанный товар в магазинах не найден"; system("pause"); return EXIT_SUCCESS; } --- Конец кода --- Ну моя идея в том чтобы добавить setName, setShop, setCost и потом get функции для них и всё так как в этом задании мне данные считывать по сути из main не надо, search тоже отдельно с возвратом потом результата. Длинновато конечно будет, но сносно (хотя в динам. структурах этот вариант реализовать будет сложно, я пока не представляю вовсе как). А как применить пользу возврата указателей в этом случае можешь написать? Или польза будет только в случае с динам. структурами? |
| HoRRoR:
--- Цитата ---(надо бы для начала добавить элемент через set в структуру же чтобы к нему обращаться) --- Конец цитаты --- Что тебе мешает обращаться к get без set? Это просто функции, обычные независимые друг от друга функции. Учись правильно выражать свои мысли, вот ты писал: --- Цитата ---если я запихну структуру в класс --- Конец цитаты --- У тебя тут нет структуры в классе. Я же описывал такую проблему: --- Код: ---struct A { int a; int b; }; class B { int c; A d; int e; public: A& getA_ref() { return d; } A* getA_ptr() { return &d; } }; ... // Тогда можно менять структуру так: B b; b.getA_ptr()->a = 0; b.getA_ref().c = 10; --- Конец кода --- --- Цитата ---Ну моя идея в том чтобы добавить setName, setShop, setCost --- Конец цитаты --- Ну так добавь, в чём проблема? --- Код: ---struct PRICE { private: char name[30];// название товара char shop[30];//;// название магазина double cost;// цена товара public: void setName(const char* name) { // Копируешь из name в this->name, проверяя длину и т.п. } void setShop(const char* name) { // Копируешь из name в shop, проверяя длину и т.п. } void setCost(double cost) { if(cost < 0.0 || cost > ...) ... this->cost = cost; } double getCost() { return cost; } }; --- Конец кода --- Возвращать имена магазина и товара можно двумя способами - либо как константную ссылку на имя (чтобы нельзя была поменять его извне), что плохо, либо копировать в передаваемый указатель на строку, что будет правильней. Типа: --- Код: --- // Часто передают ещё и размер буфера, чтобы не вылезти за рамки void getName(char* buf) { strcpy(buf, name); } --- Конец кода --- |
| gepar:
--- Цитата: HoRRoR ---У тебя тут нет структуры в классе. Я же описывал такую проблему: --- Конец цитаты --- Ну я внимательный и заметил что её там нет :) Я привёл пример структуры которую пихать буду в класс и спросил преимущества возвращения указателя, насчёт set функций это я написал предположение как бы я это делал без возвращения указателя на структуру/элемент структуры. Твой код с классом и структурой сейчас посмотрю, спасибо. И немножко отвлечённый вопрос не имеющий отношения к структурам: а класс с static элементом можно ли написав вместе с main в одном файле инициализировать (элемент) и вообще обращаться к той static переменной? Я вчера как-то в упор не мог это сделать, выдавало что-то типа "непонятная отсылка :: annualInterestRate" (притом даже если я пытался вызвать static функцию из класса для редактирования того static элемента, а не инициализировать в начале), я потом схитрил и добавил объявление класса и его элементы в .h файл после чего перед main уже смог сделать double SavingAccount::annualInterestRate=1; // SavingAccount - класс, а annualInterestRate его static элемент. |
| HoRRoR:
Выдавало что-то типа меня не интересует. Покажи код и скопируй текст ошибки - тогда смогу подсказать, а сейчас я тебя мало понимаю, несмотря на все усилия представить о чём речь. Что-то мне подсказывает, что ты просто не установил соответствующих связей. Описать класс со статическими членами перед main никто не запрещает. Непонятная отсылка - ты это так undefined reference толкуешь? Если да - то и правда связи не установил, т.е. твой код не знает о существовании такого объекта, потому что он существует как-нибудь независимо - либо описан ниже, либо в другом файле без связки через заголовок или прототип. |
| gepar:
Вот слепил код воедино: --- Код: ---// Программа для рассчёта процентной ставки # include <iostream> # include <iomanip> using namespace std; class SavingAccount { public: SavingAccount(double b) { savingBalance=b; } void modifyInterestRate(double a) { if (a>0) annualInterestRate=a; } void calculateMonthlyInterest() { savingBalance+=savingBalance*((annualInterestRate/100)/12); cout<<"\nAfter charge % balance is: "<<savingBalance<<'\n'; } private: double savingBalance; static double annualInterestRate; }; int main() { SavingAccount saver1 (2000.00); SavingAccount saver2 (30000.00); double rate; cout<<"Enter rate: "; cin>>rate; saver1.modifyInterestRate(rate); cout<<"Call static function for saver1: "; saver1.calculateMonthlyInterest(); return 0; } --- Конец кода --- Ошибка: main.cpp||undefined reference to `SavingAccount::annualInterestRate'| Это происходит при любой попытке обратиться к static элементу через функцию или же при попытке просто его инициализировать . Хотя в этот раз добавив инициализацию до main double SavingAccount::annualInterestRate=1; всё получилось, я вроде вчера её в main пихал так что по сути вопрос по поводу инициализации отпал :blush: |
| HoRRoR:
Как инициализацию глобальной статической переменной можно пихать в код функции? Она инициализируется один раз при запуске программы и должна быть инициализирована глобально, т.е. вне кода функций. |
| gepar:
HoRRoR,ну сегодня мне это логично, вчера я чего-то продолжал всё же пытаться до неё добиться с main :) Добавлено позже: Такс по первому классу получилось вот такое с set функциями : --- Код: ---//Программа создаёт структру, запрашивает данные для её заполнения после //чего производит поиск по структуре введённых данных # include <iostream> # include <iomanip> # include <windows.h> using namespace std; const int size=3; class Test { public: void setName(char a[]) { strcpy(abc.name,a); } void setShop(char a[]) { strcpy(abc.shop,a); } void setCost(double a) { abc.cost=a; } void search(char a[]) // Ищет есть ли в структуре элементы с нужным нам именем { if (!(strcmp(a,abc.name))) { cout<<"Нужный вам товар есть в магазине "<<abc.shop <<"\nЕго цена составляет: "<<abc.cost<<" грн"<<"\n\n"; resultOfSeach=1; }; } static int searchs() { return resultOfSeach;//Возвращает результат поисков } private: struct PRICE { char name[30];// название товара char shop[30];//;// название магазина double cost;// цена товара }; PRICE abc; static int resultOfSeach;// Нужна чтобы знать был ли найден товар для хоть одного класса }; int Test::resultOfSeach=0; int main() { SetConsoleCP(1251); SetConsoleOutputCP(1251); char search[30]; char temp[30]; int result=0; double cost; Test xyz;//Тестовый класс Test qwerty;// Тестовый класс 2 cout<<"Введите название товара: "; cin>>temp; xyz.setName(temp); cout<<"Введите название магазина:"; cin>>temp; xyz.setShop(temp); cout<<"Введите цену товара :"; cin>>cost; xyz.setCost(cost); cout<<"Введите имя интересущего вас товара: "; cin>>search; xyz.search(search); if (!(xyz.searchs())) cout<<"Указанный товар в магазинах не найден\n"; system("pause"); return EXIT_SUCCESS; } --- Конец кода --- Только мне ведь с таким кодом уже нельзя циклом организовать "заполнение" структуры ... Тоесть нужно для каждого класса вызывать все эти функции, ещё правда можно добавить конструктор, но это тоже немножко неуклюже будет. Или по другому более "красиво" и универсально сделать не получиться? UPD: Немного изменил код, запихнул ввод данных в конструктор, вроде получше выглядит (со стороны логики и колличества строк), но помоему есть ещё вариант как упростить всё это дело :) --- Код: ---//Программа создаёт структру, запрашивает данные для её заполнения после //чего производит поиск по структуре введённых данных # include <iostream> # include <iomanip> # include <windows.h> using namespace std; const int size=3; class Test { public: Test () { char temp[30]; double cost; cout<<"Введите название товара: "; cin>>temp; setName(temp); cout<<"Введите название магазина:"; cin>>temp; setShop(temp); cout<<"Введите цену товара :"; cin>>cost; setCost(cost); } void setName(char a[]) { strcpy(abc.name,a); } void setShop(char a[]) { strcpy(abc.shop,a); } void setCost(double a) { abc.cost=a; } void search(char a[]) // Ищет есть ли в структуре элементы с нужным нам именем { if (!(strcmp(a,abc.name))) { cout<<"Нужный вам товар есть в магазине "<<abc.shop <<"\nЕго цена составляет: "<<abc.cost<<" грн"<<"\n\n"; resultOfSeach=1; }; } static int searchs() { return resultOfSeach;//Возвращает результат поисков } private: struct PRICE { char name[30];// название товара char shop[30];//;// название магазина double cost;// цена товара }; PRICE abc; static int resultOfSeach;// Нужна чтобы знать был ли найден товар для хоть одного класса }; int Test::resultOfSeach=0; int main() { SetConsoleCP(1251); SetConsoleOutputCP(1251); char search[30]; int result=0; double cost; cout<<"Класс xyz:\n"; Test xyz;//Тестовый класс cout<<"Класс qwerty:\n"; Test qwerty;// Тестовый класс 2 cout<<"Введите имя интересущего вас товара: "; cin>>search; xyz.search(search); qwerty.search(search); if (!(xyz.searchs())) cout<<"Указанный товар в магазинах не найден\n"; system("pause"); return EXIT_SUCCESS; } --- Конец кода --- |
| HoRRoR:
--- Цитата ---Только мне ведь с таким кодом уже нельзя циклом организовать "заполнение" структуры ... Тоесть нужно для каждого класса вызывать все эти функции --- Конец цитаты --- В смысле? Что значит заполнение структуры в цикле? Ты вообще о чём? В каком смысле для каждого класса вызывать функции? Ты можешь нормально изъяснять свои мысли? |
| gepar:
HoRRoR, ну изначально же всё было предельно просто, добавил цикл --- Код: --- for (int i=0;i<size;i++) { cout<<"Введите название товара: "; cin>>abc[i].name; cout<<"Введите название магазина: "; cin>>abc[i].shop; cout<<"Введите цену товара в грн: "; cin>>abc[i].cost; cout<<endl; } --- Конец кода --- и все структуры заполнены, а теперь так нельзя, хотя как я понимаю "улучшить" тот последний код что у меня есть наверное уже не получиться толком. |
| HoRRoR:
А что тебе мешает создать массив классов? |
| gepar:
HoRRoR, такой мысли не возникало ну и не видел чтобы так делали. Сейчас так и сделаю. Вот, теперь main выглядит более универсально, спасибо за подсказку :) Теперь осталось более сложное задание - динам. структуру запихнуть в класс. Если интересно то я переделал чтобы было в main вот --- Код: ---int main() { SetConsoleCP(1251); SetConsoleOutputCP(1251); char search[30]; char temp[30]; int result=0; double cost; int n; cout<<"Введите колличество магазинов: "; cin>>n; Test *a=new Test [n]; for (int i=0;i<n;i++) { cout<<"-----Магазин N"<<i+1<<"-----\n"; cout<<"Введите название товара: "; cin>>temp; a[i].setName(temp); cout<<"Введите название магазина:"; cin>>temp; a[i].setShop(temp); cout<<"Введите цену товара :"; cin>>cost; a[i].setCost(cost); } cout<<"\nВведите имя интересущего вас товара: "; cin>>search; for (int i=0;i<n;i++) a[i].search(search); if (!(a[0].searchs())) cout<<"Указанный товар в магазинах не найден\n"; system("pause"); return EXIT_SUCCESS; } --- Конец кода --- |
| gepar:
А что значит: |7|error: variable or field `print_list' declared void| ? Это случилось при попытке перенести в класс функции для работы с динам. структурой, также несмотря на то что я запихнул в класс структуру позже я создаю новую переменную abc с типом этой структуры (ListItem abc), но компилятор пишет |99|error: `ListItem' does not name a type| Почему это он внезапно перестал видеть существование структуры, она же лишь парой строк выше определена от того места где я создаю эту переменную abc. Где я мог затупить есть предположения? Могу приложить полностью код с динам. структурой этой (там дополненный функциями твой код так как структуры мне так и не начали нравиться). |
| HoRRoR:
Вот с кода и следовало начинать. Как говорится, телепаты в отпуске. |
| gepar:
Я думал это только мне ошибки непонятны, а тем кто хорошо разбирается они много о чём говорят :D Код программы с использованием ТОЛЬКО динам. структуры (работает): --- Код: ---#include <iostream> #include <cstring> using namespace std; struct ListItem { std::string data; // Хранимые в элементе списка данные ListItem *prev, *next; // Указатели на предыдущий и следующий элементы // Конструктор ListItem(const std::string data):prev(NULL),next(NULL) { this->data = data; } ListItem* getTail() { ListItem* item = this; while(item->next) item = item->next; return item; } ListItem* addToTail(const std::string data) { ListItem *item = new ListItem(data), *last = getTail(); item->prev = last; last->next = item; return item; } ListItem* findLastItem(const std::string data) { ListItem* item = this, *last = NULL; while(item->next) { if(item->data == data) { last = item; } item = item->next; } return last; } bool insertAfterLastItem(const std::string data, ListItem* list) { ListItem* last = findLastItem(data), *next_item, *prev_item, *list_last; if(!last) return false; next_item = last->next; list_last = list->getTail(); list_last->next = next_item; if(next_item) next_item->prev = list_last; list->prev = last; last->next = list; return true; } ~ListItem() { if(next) delete next; } }; void print_list(ListItem* list) { ListItem* item = list; while(item) { std::cout << item->data; item = item->next; if(item) std::cout << " "; } std::cout << std::endl; }; void assigned(ListItem* list) { ListItem* item=list; while (item) { item->data.assign(&item->data[1]); item=item->next; } }; void plus_invert (ListItem* list) { ListItem *item=list->getTail(); while (item) { list->addToTail(item->data); item = item->prev; } }; int main() { ListItem *a = new ListItem("aa1"); a->addToTail("aa2"); a->addToTail("aa3"); a->addToTail("aa4"); std::cout << "List a: "; print_list(a); ListItem *b = new ListItem("bb1"); b->addToTail("bb2"); b->addToTail("bb3"); b->addToTail("bb4"); std::cout << "List b: "; print_list(b); a->insertAfterLastItem("aa3", b); std::cout << "Merged: "; print_list(a); assigned(a); cout<<"After deleting first symbol: "; print_list(a); plus_invert(a); cout<<"After inverting (and append): "; print_list(a); delete a; return 0; } --- Конец кода --- А вот код где я пихнул всё это дело в класс и встертился с той ошибкой: --- Код: ---#include <iostream> #include <cstring> using namespace std; class Test { void print_list(ListItem* list) { ListItem* item = list; while(item) { std::cout << item->data; item = item->next; if(item) std::cout << " "; } std::cout << std::endl; }; void assigned(ListItem* list) { ListItem* item=list; while (item) { item->data.assign(&item->data[1]); item=item->next; } }; void plus_invert (ListItem* list) { ListItem *item=list->getTail(); while (item) { list->addToTail(item->data); item = item->prev; } }; struct ListItem { std::string data; // Хранимые в элементе списка данные ListItem *prev, *next; // Указатели на предыдущий и следующий элементы // Конструктор ListItem(const std::string data):prev(NULL),next(NULL) { this->data = data; } ListItem* getTail() { ListItem* item = this; while(item->next) item = item->next; return item; } ListItem* addToTail(const std::string data) { ListItem *item = new ListItem(data), *last = getTail(); item->prev = last; last->next = item; return item; } ListItem* findLastItem(const std::string data) { ListItem* item = this, *last = NULL; while(item->next) { if(item->data == data) { last = item; } item = item->next; } return last; } bool insertAfterLastItem(const std::string data, ListItem* list) { ListItem* last = findLastItem(data), *next_item, *prev_item, *list_last; if(!last) return false; next_item = last->next; list_last = list->getTail(); list_last->next = next_item; if(next_item) next_item->prev = list_last; list->prev = last; last->next = list; return true; } ~ListItem() { if(next) delete next; } } ListItem abc; }; int main() { ListItem *a = new ListItem("aa1"); a->addToTail("aa2"); a->addToTail("aa3"); a->addToTail("aa4"); std::cout << "List a: "; print_list(a); ListItem *b = new ListItem("bb1"); b->addToTail("bb2"); b->addToTail("bb3"); b->addToTail("bb4"); std::cout << "List b: "; print_list(b); a->insertAfterLastItem("aa3", b); std::cout << "Merged: "; print_list(a); assigned(a); cout<<"After deleting first symbol: "; print_list(a); plus_invert(a); cout<<"After inverting (and append): "; print_list(a); delete a; return 0; } --- Конец кода --- Изменения только в том что во втором коде я добавил класс Test и всё запихнул туда и тут же получил целую кучу ошибок. Main пока не изменял так как пока что дело даже не в том что класс не рабочий, а в том что он теперь не компилируется. Добавлено позже: Я ведь имя структуры не менял, так почему же теперь функции не воспринимают объекты типа этой структуры (в этом ведь дело как я понял) ? |
| HoRRoR:
--- Цитата ---Я думал это только мне ошибки непонятны, а тем кто хорошо разбирается они много о чём говорят --- Конец цитаты --- Честно - влом мозги напрягать. К тому же, многие ошибки выдаются далеко не в одном случае. Во-первых, у тебя ListItem объявлен ниже, чем использован. Упомяни его и выше как «struct ListItem;». Во-вторых, у тебя отсутствует ; после тела структуры внутри класса. В-третьих, ListItem у тебя описан внутри класса Test, да ещё и в приватной области. Поэтому вне класса надо писать не ListItem, а Test::ListItem, а описание перенести в область public. Функций это тоже касается. В-четвёртых, print_list - метод класса, если хочешь вызывать его без объекта класса - надо сделать его статическим (приписать static) и писать Test::print_list. То же самое касается всех остальных функций. Вообще не понимаю, зачем тебе класс, если он пока играет только роль пространства имён. Вот компилирующийся код: --- Код: ---#include <iostream> #include <cstring> using namespace std; class Test { public: struct ListItem; static void print_list(ListItem* list) { ListItem* item = list; while(item) { std::cout << item->data; item = item->next; if(item) std::cout << " "; } std::cout << std::endl; }; static void assigned(ListItem* list) { ListItem* item=list; while (item) { item->data.assign(&item->data[1]); item=item->next; } }; static void plus_invert (ListItem* list) { ListItem *item=list->getTail(); while (item) { list->addToTail(item->data); item = item->prev; } }; struct ListItem { std::string data; // Хранимые в элементе списка данные ListItem *prev, *next; // Указатели на предыдущий и следующий элементы // Конструктор ListItem(const std::string data):prev(NULL),next(NULL) { this->data = data; } ListItem* getTail() { ListItem* item = this; while(item->next) item = item->next; return item; } ListItem* addToTail(const std::string data) { ListItem *item = new ListItem(data), *last = getTail(); item->prev = last; last->next = item; return item; } ListItem* findLastItem(const std::string data) { ListItem* item = this, *last = NULL; while(item->next) { if(item->data == data) { last = item; } item = item->next; } return last; } bool insertAfterLastItem(const std::string data, ListItem* list) { ListItem* last = findLastItem(data), *next_item, *prev_item, *list_last; if(!last) return false; next_item = last->next; list_last = list->getTail(); list_last->next = next_item; if(next_item) next_item->prev = list_last; list->prev = last; last->next = list; return true; } ~ListItem() { if(next) delete next; } }; ListItem abc; }; int main() { Test::ListItem *a = new Test::ListItem("aa1"); a->addToTail("aa2"); a->addToTail("aa3"); a->addToTail("aa4"); std::cout << "List a: "; Test::print_list(a); Test::ListItem *b = new Test::ListItem("bb1"); b->addToTail("bb2"); b->addToTail("bb3"); b->addToTail("bb4"); std::cout << "List b: "; Test::print_list(b); a->insertAfterLastItem("aa3", b); std::cout << "Merged: "; Test::print_list(a); Test::assigned(a); cout<<"After deleting first symbol: "; Test::print_list(a); Test::plus_invert(a); cout<<"After inverting (and append): "; Test::print_list(a); delete a; return 0; } --- Конец кода --- |
| gepar:
--- Цитата: HoRRoR ---Вообще не понимаю, зачем тебе класс, если он пока играет только роль пространства имён. --- Конец цитаты --- Это не ко мне с такими вопросами, это мне задали такое в универе, я бы сам тоже до такого изврата не дошёл :) За подсказки спасибо, сейчас буду учитывать и вносить изменения. Хотя чем поможет print_list как статическая функция пока не понял, сейчас методом проб и ошибок буду с ней воевать :) P.S Test::ListItem *a = new Test::ListItem("aa1") - хитро ты это, не знал что так можно обратиться к структуре в классе, когда у нас ни один класс не создан. |
| HoRRoR:
Понимай разницу между классом и объектом класса. Класс у тебя создан - это код. Объект класса - это переменная этого класса. --- Цитата ---Хотя чем поможет print_list как статическая функция пока не понял --- Конец цитаты --- В смысле? Ты пытался её вызывать без объекта класса. Это можно делать только со статическими функциями. Тем более, что функция с полями класса не взаимодействует - она по логике и должна быть описана как статическая. |
| Навигация |
| Главная страница сообщений |
| Следующая страница |
| Предыдущая страница |