Автор Тема: Програмирование на C++  (Прочитано 76702 раз)

0 Пользователей и 2 Гостей просматривают эту тему.

Оффлайн HoRRoR

  • Пользователь
  • Сообщений: 983
  • Пол: Мужской
  • Ромхакер
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #120 : 27 Февраль 2011, 22:20:00 »
Э, а ничего, что у тебя прототип не соответствует функции? Т.е. это описания двух разных функций. Либо приведи их к общему виду, либо перенеси функцию выше мэйна и не используй прототип.

Оффлайн gepar

  • Пользователь
  • Сообщений: 10150
  • Пол: Мужской
  • ▂ ▃ ▄ ▅ ▆ ▇ █
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #121 : 01 Март 2011, 00:22:17 »
Отложу немножко указатели, чтобы потом к ним вернуться, так как у меня тут появилось "чудное" задание: переделать лабы на структуры, но с использованием классов и структур одновременно (это если я всё правильно понял), собственно возник вопрос: если я запихну структуру в класс, то как я из main напрямую для конкретного созданного мной класса потом к ней смогу обратиться? Получается никак чтоли и мне нужно делать целую кучу set и get функций для каждой строчки структуры для того чтобы работать с той структурой в классе?  :(

Оффлайн HoRRoR

  • Пользователь
  • Сообщений: 983
  • Пол: Мужской
  • Ромхакер
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #122 : 01 Март 2011, 00:48:05 »
Зачем? Возвращай через get ссылку или указатель на структуру и делов-то.

Оффлайн gepar

  • Пользователь
  • Сообщений: 10150
  • Пол: Мужской
  • ▂ ▃ ▄ ▅ ▆ ▇ █
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #123 : 02 Март 2011, 01:07:03 »
Я тебья не панимать патаму шта я изучать с++, но не знать его полнастью  :) Я пока возвращал указатели только с целью построения каскадного вызова функции, учитывая что я get с ходу применить не могу (надо бы для начала добавить элемент через set в структуру же чтобы к нему обращаться) то мне получается надо сделать кучу set функций ну и вообще получив указатель на элемент структуры я ведь не смогу узнать адрес сл. элемента так как в структуре элементы же строки... или я опять что-то не так понял.
Вот мой пример по структурам что надо пихнуть в класс теперь (динамические пока не трогаю, на обычных думаю понять тебя проще будет):
Ну моя идея в том чтобы добавить setName, setShop, setCost и потом get функции для них и всё так как в этом задании мне данные считывать по сути из main не надо, search тоже отдельно с возвратом потом результата. Длинновато конечно будет, но сносно (хотя в динам. структурах этот вариант реализовать будет сложно, я пока не представляю вовсе как). А как применить пользу возврата указателей в этом случае можешь написать? Или польза будет только в случае с динам. структурами?

Оффлайн HoRRoR

  • Пользователь
  • Сообщений: 983
  • Пол: Мужской
  • Ромхакер
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #124 : 02 Март 2011, 11:36:17 »
Цитата
(надо бы для начала добавить элемент через 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);
    }
« Последнее редактирование: 02 Март 2011, 11:40:08 от HoRRoR »

Оффлайн gepar

  • Пользователь
  • Сообщений: 10150
  • Пол: Мужской
  • ▂ ▃ ▄ ▅ ▆ ▇ █
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #125 : 02 Март 2011, 16:26:35 »
Цитата: HoRRoR
У тебя тут нет структуры в классе. Я же описывал такую проблему:
Ну я внимательный и заметил что её там нет  :) Я привёл пример структуры которую пихать буду в класс и спросил преимущества возвращения указателя, насчёт set функций это я написал предположение как бы я это делал без возвращения указателя на структуру/элемент структуры. Твой код с классом и структурой сейчас посмотрю, спасибо.

И немножко отвлечённый вопрос не имеющий отношения к структурам: а класс с static элементом можно ли написав вместе с main в одном файле инициализировать (элемент) и вообще обращаться к той static переменной? Я вчера как-то в упор не мог это сделать, выдавало что-то типа "непонятная отсылка :: annualInterestRate" (притом даже если я пытался вызвать static функцию из класса для редактирования того static элемента, а не инициализировать в начале), я потом схитрил и добавил объявление класса и его элементы в .h файл после чего перед main уже смог сделать
double SavingAccount::annualInterestRate=1; // SavingAccount - класс, а annualInterestRate его static элемент.

Оффлайн HoRRoR

  • Пользователь
  • Сообщений: 983
  • Пол: Мужской
  • Ромхакер
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #126 : 02 Март 2011, 17:22:44 »
Выдавало что-то типа меня не интересует. Покажи код и скопируй текст ошибки - тогда смогу подсказать, а сейчас я тебя мало понимаю, несмотря на все усилия представить о чём речь. Что-то мне подсказывает, что ты просто не установил соответствующих связей. Описать класс со статическими членами перед main никто не запрещает.
Непонятная отсылка - ты это так undefined reference толкуешь? Если да - то и правда связи не установил, т.е. твой код не знает о существовании такого объекта, потому что он существует как-нибудь независимо - либо описан ниже, либо в другом файле без связки через заголовок или прототип.
« Последнее редактирование: 02 Март 2011, 17:24:55 от HoRRoR »

Оффлайн gepar

  • Пользователь
  • Сообщений: 10150
  • Пол: Мужской
  • ▂ ▃ ▄ ▅ ▆ ▇ █
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #127 : 02 Март 2011, 17:38:02 »
Вот слепил код воедино:
// Программа для рассчёта процентной ставки
# 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:
« Последнее редактирование: 02 Март 2011, 17:40:06 от gepar »

Оффлайн HoRRoR

  • Пользователь
  • Сообщений: 983
  • Пол: Мужской
  • Ромхакер
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #128 : 02 Март 2011, 19:49:05 »
Как инициализацию глобальной статической переменной можно пихать в код функции? Она инициализируется один раз при запуске программы и должна быть инициализирована глобально, т.е. вне кода функций.

Оффлайн gepar

  • Пользователь
  • Сообщений: 10150
  • Пол: Мужской
  • ▂ ▃ ▄ ▅ ▆ ▇ █
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #129 : 02 Март 2011, 23:44:14 »
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: Немного изменил код, запихнул ввод данных в конструктор, вроде получше выглядит (со стороны логики и колличества строк), но помоему есть ещё вариант как упростить всё это дело  :)
« Последнее редактирование: 03 Март 2011, 00:00:56 от gepar »

Оффлайн HoRRoR

  • Пользователь
  • Сообщений: 983
  • Пол: Мужской
  • Ромхакер
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #130 : 03 Март 2011, 00:11:30 »
Цитата
Только мне ведь с таким кодом уже нельзя циклом организовать "заполнение" структуры ... Тоесть нужно для каждого класса вызывать все эти функции
В смысле? Что значит заполнение структуры в цикле? Ты вообще о чём? В каком смысле для каждого класса вызывать функции? Ты можешь нормально изъяснять свои мысли?

Оффлайн gepar

  • Пользователь
  • Сообщений: 10150
  • Пол: Мужской
  • ▂ ▃ ▄ ▅ ▆ ▇ █
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #131 : 03 Март 2011, 00:47:45 »
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

  • Пользователь
  • Сообщений: 983
  • Пол: Мужской
  • Ромхакер
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #132 : 03 Март 2011, 09:10:04 »
А что тебе мешает создать массив классов?

Оффлайн gepar

  • Пользователь
  • Сообщений: 10150
  • Пол: Мужской
  • ▂ ▃ ▄ ▅ ▆ ▇ █
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #133 : 03 Март 2011, 12:02:11 »
HoRRoR, такой мысли не возникало ну и не видел чтобы так делали. Сейчас так и сделаю.
Вот, теперь main выглядит более универсально, спасибо за подсказку  :) Теперь осталось более сложное задание - динам. структуру запихнуть в класс.
Если интересно то я переделал чтобы было в main вот
« Последнее редактирование: 03 Март 2011, 12:13:19 от gepar »

Оффлайн gepar

  • Пользователь
  • Сообщений: 10150
  • Пол: Мужской
  • ▂ ▃ ▄ ▅ ▆ ▇ █
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #134 : 03 Март 2011, 22:43:04 »
А что значит:
|7|error: variable or field `print_list' declared void|
?
Это случилось при попытке перенести в класс функции для работы с динам. структурой, также несмотря на то что я запихнул в класс структуру позже я создаю новую переменную abc с типом этой структуры (ListItem abc), но компилятор пишет
|99|error: `ListItem' does not name a type|
Почему это он внезапно перестал видеть существование структуры, она же лишь парой строк выше определена от того места где я создаю эту переменную abc.
Где я мог затупить есть предположения? Могу приложить полностью код с динам. структурой этой (там дополненный функциями твой код так как структуры мне так и не начали нравиться).
« Последнее редактирование: 03 Март 2011, 22:45:19 от gepar »

Оффлайн HoRRoR

  • Пользователь
  • Сообщений: 983
  • Пол: Мужской
  • Ромхакер
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #135 : 03 Март 2011, 22:54:06 »
Вот с кода и следовало начинать. Как говорится, телепаты в отпуске.

Оффлайн gepar

  • Пользователь
  • Сообщений: 10150
  • Пол: Мужской
  • ▂ ▃ ▄ ▅ ▆ ▇ █
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #136 : 03 Март 2011, 23:04:38 »
Я думал это только мне ошибки непонятны, а тем кто хорошо разбирается они много о чём говорят  :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

  • Пользователь
  • Сообщений: 983
  • Пол: Мужской
  • Ромхакер
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #137 : 03 Март 2011, 23:28:01 »
Цитата
Я думал это только мне ошибки непонятны, а тем кто хорошо разбирается они много о чём говорят 
Честно - влом мозги напрягать. К тому же, многие ошибки выдаются далеко не в одном случае.

Во-первых, у тебя 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

  • Пользователь
  • Сообщений: 10150
  • Пол: Мужской
  • ▂ ▃ ▄ ▅ ▆ ▇ █
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #138 : 04 Март 2011, 20:11:56 »
Цитата: HoRRoR
Вообще не понимаю, зачем тебе класс, если он пока играет только роль пространства имён.
Это не ко мне с такими вопросами, это мне задали такое в универе, я бы сам тоже до такого изврата не дошёл  :)
За подсказки спасибо, сейчас буду учитывать и вносить изменения. Хотя чем поможет print_list как статическая функция пока не понял, сейчас методом проб и ошибок буду с ней воевать  :)
P.S Test::ListItem *a = new Test::ListItem("aa1") - хитро ты это, не знал что так можно обратиться к структуре в классе, когда у нас ни один  класс не создан.

Оффлайн HoRRoR

  • Пользователь
  • Сообщений: 983
  • Пол: Мужской
  • Ромхакер
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #139 : 04 Март 2011, 20:32:33 »
Понимай разницу между классом и объектом класса. Класс у тебя создан - это код. Объект класса - это переменная этого класса.
Цитата
Хотя чем поможет print_list как статическая функция пока не понял
В смысле? Ты пытался её вызывать без объекта класса. Это можно делать только со статическими функциями. Тем более, что функция с полями класса не взаимодействует - она по логике и должна быть описана как статическая.

Оффлайн gepar

  • Пользователь
  • Сообщений: 10150
  • Пол: Мужской
  • ▂ ▃ ▄ ▅ ▆ ▇ █
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #140 : 07 Март 2011, 16:36:44 »
Так, пробую дальше продвигаться по Дейтелу. Дальше у него тут перегрузка операторов, с перегрузкой ввода в поток и вывода из потока, которые были глобальными всё получилось, а вот дальше что-то я не так смотрю указываю когда операторы для  перегрузки находятся в классе. Вообще это пример из Дейтела, только у него он как всегда разбит на кучу файлов, я же вот попробовал переделать чтобы всё было в одном и что-то упустил наверное, подскажите пожалуйста что именно.
# include <iostream>
# include <iomanip>
# include <cstdlib>
using namespace std;

class Array
{
    friend istream &operator>>(istream &input, Array &a);
    friend ostream &operator<<(ostream &output, const Array &a);
public:

    Array (int arraySize=10)
    {
        size=(arraySize>0 ? arraySize : 10);
        ptr=new int[size];
        for (int i=0;i<size;i++)
         ptr[i]=0;
    }

    Array (const Array &arrayToCopy)
     :size (arrayToCopy.size)
    {
        ptr=new int[size];
        for (int i=0;i<size;i++)
         ptr[i]=arrayToCopy.ptr[i];
    }

    ~Array()
    {
        delete [] ptr;
    }

    int getSize() const
    {
        return size;
    }

    const &Array operator=(const Array &right)
    {
        if (&right!=this)
        {
            if (size!=right.size)
            {
                delete [] ptr;
                size=right.size;
                ptr=new int [size];
            }
            for (int i=0;i<size;i++)
             ptr[i]=right.ptr[i];
        }
        return *this;
    }

    bool operator==(const Array &right) const
    {
        if (size!=right.size)
         return false;
        for (int i=0;i<size;i++)
         if (ptr[i]!=right.ptr[i])
          return false;
        return true;
    }

    bool operator!=(const Array &right) const
    {
        return !(*this==right);
    }

    int &Array operator [](int subscript)
    {
        if (subscript<0 || subscript >=size)
        {
            cerr<<"\nError: Subscript "<<subscript
            <<" out of range"<<endl;
            exit (1);
        }
        return ptr[subscript];
    }

    int Array operator[](int subscript) const
    {
        if (subscript<0 || subscript>=size)
        {
            cerr<<"\nError: Subscript "<<subscript
            <<" out of range"<<endl;
            exit (1);
        }
        return ptr[subscript];
    };

private:
    int size;
    int *ptr;
};

istream &operator>>(istream &input, Array &a)
{
    for (int i=0;i<a.size;i++)
     input>>a.ptr[i];
    return input;
};

ostream &operator<<(ostream &output, const Array &a)
{
    int i;
    for (i=0;i<a.size;i++)
    {
        output<<setw(12)<<a.ptr[i];
        if ((i+1)%4==0)
         output<<endl;
    }
    if (i%4!=0)
     output<<endl;

    return output;
};

int main()
{
   Array intgers1(7);
   Array integers2;
   return 0;
}
Сорри комментариев не писал, но они я думаю не надо сейчас. Назначение класса - сделать свой массив с блекджеком и девушками с проверкой не был ли выход за границы массива и с возможностью печати/заполнения/сравнения массива int чисел.
Ошибки компилятор выдаёт только в тех строчках где идёт объявление перегрузки операторов
const &Array operator=(const Array &right)
bool operator==(const Array &right) const
int &Array operator [](int subscript)
int Array operator[](int subscript) const
Я что-то не дописал / написал лишнее в этих строчках?
« Последнее редактирование: 07 Март 2011, 16:40:08 от gepar »

Оффлайн HoRRoR

  • Пользователь
  • Сообщений: 983
  • Пол: Мужской
  • Ромхакер
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #141 : 07 Март 2011, 18:19:46 »
Что есть &Array? Array& пиши, чтобы ссылку объявить.
int Array - ещё лучше... Чего же тогда не int string double сразу? :D Определись уже с типом.

Оффлайн gepar

  • Пользователь
  • Сообщений: 10150
  • Пол: Мужской
  • ▂ ▃ ▄ ▅ ▆ ▇ █
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #142 : 07 Март 2011, 18:37:18 »
HoRRoR,ну Array это и есть этот класс собственно, если убрать Array то компилятор говорит что я пытаюсь заменить оператор для непонятно чего. Инымы словами это
const &Array operator=(const Array &right)
должно позволить присваивать одному объекту класса Array значения другого объекта класса Array , при этом естественно просто будет сделана копия элементов из одного класса (того что будет справа от = (right) тому что будет слева от = ) в другой.

Оффлайн HoRRoR

  • Пользователь
  • Сообщений: 983
  • Пол: Мужской
  • Ромхакер
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #143 : 07 Март 2011, 19:48:01 »
Ты вообще читаешь то, что я пишу? Замени &Array на Array&.

Оффлайн gepar

  • Пользователь
  • Сообщений: 10150
  • Пол: Мужской
  • ▂ ▃ ▄ ▅ ▆ ▇ █
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #144 : 08 Март 2011, 00:19:14 »
Упростим задачу, вот код с дописанными комментариями  :)
# include <iostream>
# include <iomanip>
# include <cstdlib>
using namespace std;

class Array
{
    friend istream &operator>>(istream &input, Array &a); // ввод данных в класс Array через cin
    friend ostream &operator<<(ostream &output, const Array &a);// вывод данных класса Array через cout
public:

//конструктор выделяет место под нужное колличество элементов массива
//по умолчанию на 10 элементов
    Array (int arraySize=10)
    {
        size=(arraySize>0 ? arraySize : 10);
        ptr=new int[size];
        for (int i=0;i<size;i++)
         ptr[i]=0;
    }
//конструктор копии Array (чтобы можно было сделать array1(array2))
    Array (const Array &arrayToCopy)
     :size (arrayToCopy.size)
    {
        ptr=new int[size];
        for (int i=0;i<size;i++)
         ptr[i]=arrayToCopy.ptr[i];
    }

//деструктор
    ~Array()
    {
        delete [] ptr;
    }

//возвращает размер массива
    int getSize() const
    {
        return size;
    }

//перегрузка оператора присваивания для класса Array
    Array operator=(const Array &right)
    {
        if (&right!=this)
        {
            if (size!=right.size)
            {
                delete [] ptr;
                size=right.size;
                ptr=new int [size];
            }
            for (int i=0;i<size;i++)
             ptr[i]=right.ptr[i];
        }
        return *this;
    }
//определения равны ли два массива
    bool operator==(const Array &right) const
    {
        if (size!=right.size)
         return false;
        for (int i=0;i<size;i++)
         if (ptr[i]!=right.ptr[i])
          return false;
        return true;
    }

//определение не равенства двух массивов
    bool operator!=(const Array &right) const
    {
        return !(*this==right);
    }

//возможность обращения к нужному элементу массива
//возвращает указатель на этот элемент чтобы обеспечить присваивание
//НЕ РАБОТАЕТ
    Array operator [](int subscript)
    {
        if (subscript<0 || subscript >=size)
        {
            cerr<<"\nError: Subscript "<<subscript
            <<" out of range"<<endl;
            exit (1);
        }
        return ptr[subscript];
    }

//возможность обращения к нужному элементу массива для const даных
    Array operator[](int subscript) const
    {
        if (subscript<0 || subscript>=size)
        {
            cerr<<"\nError: Subscript "<<subscript
            <<" out of range"<<endl;
            exit (1);
        }
        return ptr[subscript];
    };

private:
    int size; //размер массива
    int *ptr; //указатель на данные массива
};

istream &operator>>(istream &input, Array &a)
{
    for (int i=0;i<a.size;i++)
     input>>a.ptr[i];
    return input;
};

ostream &operator<<(ostream &output, const Array &a)
{
    int i;
    for (i=0;i<a.size;i++)
    {
        output<<setw(12)<<a.ptr[i];
        if ((i+1)%4==0)
         output<<endl;
    }
    if (i%4!=0)
     output<<endl;

    return output;
};

int main()
{
   Array integers1(7);
   Array integers2;
   cout<<integers1;
   integers1[4]=100;//не изменяет integers1[4] так как функция получает копию
   cout<<integers1;
   return 0;
}
Код компилируется, но беда в другом - при перегрузке операторов передаются копии. При попытке написать например
Array& operator[](int subscript) const
я получаю ошибку что у меня там мол дальше возвращается же ссылка на int данные и мол так нельзя. Пишу
int &operator[](int subscript) const
опять же таки всё компилируется но блин опять же таки нужный объект класса не модифицируется (это видно по выводу данных до и после попытки заменить 4 элемент массива в main).
 

Добавлено позже:
А, тьфу, я редактировал функцию что для const данных, тогда там просто int &operator[](int subscript) const и всё будет работать. Короче вот так тогда должно быть:
# include <iostream>
# include <iomanip>
# include <cstdlib>
using namespace std;

class Array
{
    friend istream &operator>>(istream &input, Array &a); // ввод данных в класс Array через cin
    friend ostream &operator<<(ostream &output, const Array &a);// вывод данных класса Array через cout
public:

//конструктор выделяет место под нужное колличество элементов массива
//по умолчанию на 10 элементов
    Array (int arraySize=10)
    {
        size=(arraySize>0 ? arraySize : 10);
        ptr=new int[size];
        for (int i=0;i<size;i++)
         ptr[i]=0;
    }
//конструктор копии Array (чтобы можно было сделать array1(array2))
    Array (const Array &arrayToCopy)
     :size (arrayToCopy.size)
    {
        ptr=new int[size];
        for (int i=0;i<size;i++)
         ptr[i]=arrayToCopy.ptr[i];
    }

//деструктор
    ~Array()
    {
        delete [] ptr;
    }

//возвращает размер массива
    int getSize() const
    {
        return size;
    }

//перегрузка оператора присваивания для класса Array
    Array &operator=(const Array &right)
    {
        if (&right!=this)
        {
            if (size!=right.size)
            {
                delete [] ptr;
                size=right.size;
                ptr=new int [size];
            }
            for (int i=0;i<size;i++)
             ptr[i]=right.ptr[i];
        }
        return *this;
    }
//определения равны ли два массива
    bool operator==(const Array &right) const
    {
        if (size!=right.size)
         return false;
        for (int i=0;i<size;i++)
         if (ptr[i]!=right.ptr[i])
          return false;
        return true;
    }

//определение не равенства двух массивов
    bool operator!=(const Array &right) const
    {
        return !(*this==right);
    }

//возможность обращения к нужному элементу массива
//возвращает указатель на этот элемент чтобы обеспечить присваивание
    int &operator [](int subscript)
    {
        if (subscript<0 || subscript >=size)
        {
            cerr<<"\nError: Subscript "<<subscript
            <<" out of range"<<endl;
            exit (1);
        }
        return ptr[subscript];
    }

//возможность обращения к нужному элементу массива для const даных
    int operator[](int subscript) const
    {
        if (subscript<0 || subscript>=size)
        {
            cerr<<"\nError: Subscript "<<subscript
            <<" out of range"<<endl;
            exit (1);
        }
        return ptr[subscript];
    };

private:
    int size; //размер массива
    int *ptr; //указатель на данные массива
};

istream &operator>>(istream &input, Array &a)
{
    for (int i=0;i<a.size;i++)
     input>>a.ptr[i];
    return input;
};

ostream &operator<<(ostream &output, const Array &a)
{
    int i;
    for (i=0;i<a.size;i++)
    {
        output<<setw(12)<<a.ptr[i];
        if ((i+1)%4==0)
         output<<endl;
    }
    if (i%4!=0)
     output<<endl;

    return output;
};

int main()
{
   Array integers1(7);
   Array integers2;
   cout<<integers1;
   integers1[4]=100;//не изменяет integers1[4] так как функция получает копию
   cout<<integers1;
   return 0;
}
Сейчас только в main протестирую всё ли работает теперь как положено.

Добавлено позже:
HoRRoR,читаю, просто этот совет твой не для всех функций помог, ну да я уже "добил" этот класс и теперь вроде перегрузка операторов стала понятнее.

Добавлено позже:
Небольшой вопрос на тему правильно ли я понял:
если у меня идёт перегрузка оператора "внутри" класса и она возвращает что-то (в данном случае ссылку на данные типа int) то я пишу так:
    int operator[](int subscript) const
    {
        if (subscript<0 || subscript>=size)
        {
            cerr<<"\nError: Subscript "<<subscript
            <<" out of range"<<endl;
            exit (1);
        }
        return ptr[subscript];
    };
А если ничего не возвращает или возвращает указатель *this то я вместо того чтобы написать void должен писать имя класса, так?

Оффлайн HoRRoR

  • Пользователь
  • Сообщений: 983
  • Пол: Мужской
  • Ромхакер
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #145 : 08 Март 2011, 00:58:14 »
Ты в любом случае пишешь возвращаемый тип. *this - объект типа данного класса, т.е. да, ты должен писать имя класса в качестве типа возвращаемого объекта. Если ничего не возвращает (правда зачем тебе такой оператор?) - то void, естественно.

Цитата
(в данном случае ссылку на данные типа int)
У тебя тут не ссылка, а просто int.

Оффлайн gepar

  • Пользователь
  • Сообщений: 10150
  • Пол: Мужской
  • ▂ ▃ ▄ ▅ ▆ ▇ █
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #146 : 08 Март 2011, 11:56:13 »
HoRRoR, ну как зачем?  :) Ну вот набросок маленький опять на ту же самую тему (создание своего массива), фантазии что-то у меня вчера не хватило по поводу темы очередной программы-примера  :) Здесь меньше проверок, но дело не в них, посмотри пожалуйста на перегрузку оператора присваивания, там я уже в комментарии расписал что получается если указать void (несмотря на то что класс ничего не возвращает) поэтому я оставил как тип название класса (Test).

# include <iostream>
# include <iomanip>
using namespace std;

class Test
{
    friend ostream &operator<<( ostream &output, Test &a);//перегрузка глобального оператора вывода
public:
    Test(int a=10)//конструктор для нового "массива"
    {
        size=a;
        ptr=new int [size];
        for (int i=0;i<size;i++)
         ptr[i]=0;
    }

//перегрузка оператора =
//по сути ведь нужен void так как вызов же будет
//что-то типа xyz.operator=(abc)
//+ ничего возвращать ведь не надо, но
//если написать void то компилятор будет ругаться
//на строку 24(где открывается { со сл. ошибкой:
// 24|error: cannot declare reference to `void'|

    Test &operator=(Test b)
    {
        for (int i=0;i<size;i++)
         this->ptr[i]=b.ptr[i];
    }


    int &operator[](int x)// перегрузка [] для обращения к нужному элементу "массива"
    {
        return this->ptr[x];
    }

private:
    int size;// размер массива
    int *ptr; // указатель на него (массив)
};

ostream &operator<<( ostream &output, Test &a)
{
    for (int i=0;i<a.size;i++)
     output<<a.ptr[i]<<" ";
    output<<'\n';
}

int main()
{
    Test abc(5);// новый "массив" размером 5
    Test xyz(5);
    cout<<abc;//вывод abc
    abc[3]=100;//изменяем 3ий элемент на 100
    xyz=abc;//присваиваем xyz значения abc
    cout<<xyz;//проверяем было ли присваивание
    cout<<abc;//проверяем равен ли 100 3ий элемент
    return 0;
}


Оффлайн HoRRoR

  • Пользователь
  • Сообщений: 983
  • Пол: Мужской
  • Ромхакер
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #147 : 08 Март 2011, 12:36:00 »
Ну я думал ты это про [] говоришь.
А ошибка у тебя потому что нехрен ссылку типа void делать. Вот читаешь ты учебник, а толку, если ляпы у тебя детские? Убери амперсант, тогда сможешь void написать. Вчитывался бы хотя бы в текст ошибок...
« Последнее редактирование: 08 Март 2011, 12:38:37 от HoRRoR »

Оффлайн gepar

  • Пользователь
  • Сообщений: 10150
  • Пол: Мужской
  • ▂ ▃ ▄ ▅ ▆ ▇ █
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #148 : 08 Март 2011, 13:04:58 »
Цитата: HoRRoR
А ошибка у тебя потому что нехрен ссылку типа void делать.
:) Так я же думал что & относиться к operator=, а не к void. Всегда ведь & относиться к тому что за ним написано, а не перед.

Оффлайн HoRRoR

  • Пользователь
  • Сообщений: 983
  • Пол: Мужской
  • Ромхакер
    • Просмотр профиля
Re: Програмирование на C++
« Ответ #149 : 08 Март 2011, 13:53:44 »
Скажи мне, какой тогда, на твой взгляд, он нёс функционал? Ты всегда пишешь операторы с неизвестным тебе функционалом?
int* - тип, звёздочка относится к инту. int& - то же самое. int *abc - объявление переменной, звёздочка относится к abc.