Форум программистов, компьютерный форум CyberForum.ru

Вектор объектов класса - C++

Восстановить пароль Регистрация
 
HEYDEPZHUMblU
0 / 0 / 0
Регистрация: 06.06.2016
Сообщений: 18
04.07.2016, 17:49     Вектор объектов класса #1
Всем привет! Несколько недель назад я писал сюда по поводу одной задачи. Она заключается в том, чтобы реализовать класс "Зоомагазин" с полями: тип животного, пол, цена, количество, а также придумать для этого класса функционал. Я решил сделать функции добавления животных в магазин, просмотр списка животных и их покупка. Для того, чтобы удалять животных из списка при покупке, я решил использовать вектор, в котором будут храниться объекты класса. С вектором возникла проблема, так как при выводе полного списка животных в каждой строке таблицы отображаются данные последнего введённого животного. Когда я использовал массив объектов класса, всё отображалось корректно. Подскажите, как решить эту проблему?

Заголовочный файл:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#pragma once
#ifndef ZOO_H
#define ZOO_H
 
#include <string>
 
using namespace std;
 
class Zoo
{
    private:
        string *type;
        string *gender;
        double *price;
        int *amount;
    public:
        Zoo();
        virtual ~Zoo();
        void Menu();
        void getAll();
        void setAll();
        void table();
};
 
#endif
Исполнительный файл:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include "Zoo.h"
#include <iostream>
#include <iomanip>
 
using namespace std;
 
Zoo::Zoo()
{
    type = new string("animal");
    gender = new string("male");
    price = new double(0);
    amount = new int(0);
}
 
Zoo::~Zoo()
{
 
}
 
void Zoo::Menu()
{
    cout << "Select action." << endl;
    cout << "1. Look all the animals;" << endl;
    cout << "2. Add animal;" << endl;
    cout << "3. Buy animal;" << endl;
    cout << "4. Exit." << endl << endl;
}
 
void Zoo::table()
{
    cout<<endl;
    cout<<"||===========||==========||=========||==========||"<<endl;
    cout<<"||Animal type||  Gender  ||  Price  ||  Amount  ||"<<endl;
    cout<<"||===========||==========||=========||==========||"<<endl;
}
 
void Zoo::getAll()
{
    cout << "||";
    if (type->length()%2==0)
    {
        cout<<setw((11-type->length())/2+type->length())<<*type<<setw((11-type->length())/2+3)<<"||";
    }
    else
    {
        cout<<setw((11-type->length())/2+type->length())<<*type<<setw((11-type->length())/2+2)<<"||";
    }
    if (gender->length()%2==0)
    {
        cout<<setw((10-gender->length())/2+gender->length())<<*gender<<setw((10-gender->length())/2+2)<<"||";
    }
    else
    {
        cout<<setw((10-gender->length())/2+gender->length())<<*gender<<setw((10-gender->length())/2+3)<<"||";
    }
    cout<<setw(9)<<fixed<<setprecision(2)<<*price<<"||";
    cout<<setw(10)<<*amount<<"||";
    cout<<endl<<"||===========||==========||=========||==========||"<<endl;
}
 
void Zoo::setAll()
{
    cout << "Animal type: "; cin >> *type;
    cout << "Gender: "; cin >> *gender;
    cout << "Price: "; cin >> *price;
    cout << "Amount: "; cin >> *amount;
}
Основная программа:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
#include "Zoo.h"
#include <vector>
 
using namespace std;
 
int main()
{
    cout << "Hello" << endl;
    vector <Zoo> Animal;
    Zoo obj;
    Zoo *ptr_obj = &obj;
    ptr_obj->Menu();
    int enter = 0;
    while (enter != 4)
    {
        cin >> enter;
        switch(enter)
        {
            case 1:
                if (Animal.size() == 0)
                {
                    cout << "There is no animals in the shop now." << endl;
                }
                else
                {
                    ptr_obj->table();
                    for (unsigned int i = 0; i < Animal.size(); i++)
                    {
                        Animal[i].getAll();
                    }
                }
                break;
            case 2:
                ptr_obj->setAll();
                Animal.push_back(obj);
                break;
            case 3:
 
                break;
        }
    }
    return 0;
}
Лучшие ответы (1)
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Хрисипп
 Аватар для Хрисипп
17 / 27 / 8
Регистрация: 09.02.2016
Сообщений: 212
04.07.2016, 19:24     Вектор объектов класса #2
Цитата Сообщение от HEYDEPZHUMblU Посмотреть сообщение
Zoo::Zoo()
{
type = new string("animal");
gender = new string("male");
price = new double(0);
amount = new int(0);
}
у тебя каждый ссылается на определенный участок памяти, а соответственно и изменяет один участок памяти. вот отчего у тебя все и одинаково

Добавлено через 4 минуты
лучше не играться с динамической памятью, пока обучаешься
zss
Модератор
Эксперт С++
 Аватар для zss
5943 / 5548 / 1783
Регистрация: 18.12.2011
Сообщений: 14,167
Завершенные тесты: 1
04.07.2016, 19:31     Вектор объектов класса #3
Использование указателей в данной задаче ничем не обосновано.
И, к тому же, Вы совсем не следите за удалением созданных динамических объектов.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include <string>
#include <iostream>
#include <iomanip>
#include <vector>
 
using namespace std;
 
class Zoo
{
private:
    string type;
    string gender;
    double price;
    int amount;
public:
    Zoo();
    virtual ~Zoo();
    void Menu();
    void getAll();
    void setAll();
    void table();
};
Zoo::Zoo()
{
    type = "animal";
    gender = "male";
    price = 0;
    amount = 0;
}
 
Zoo::~Zoo()
{
 
}
 
void Zoo::Menu()
{
    cout << "Select action." << endl;
    cout << "1. Look all the animals;" << endl;
    cout << "2. Add animal;" << endl;
    cout << "3. Buy animal;" << endl;
    cout << "4. Exit." << endl << endl;
}
 
void Zoo::table()
{
    cout<<endl;
    cout<<"||===========||==========||=========||==========||"<<endl;
    cout<<"||Animal type||  Gender  ||  Price  ||  Amount  ||"<<endl;
    cout<<"||===========||==========||=========||==========||"<<endl;
}
 
void Zoo::getAll()
{
    cout << "||";
    if (type.length()%2==0)
    {
        cout<<setw((11-type.length())/2+type.length())<<type<<setw((11-type.length())/2+3)<<"||";
    }
    else
    {
        cout<<setw((11-type.length())/2+type.length())<<type<<setw((11-type.length())/2+2)<<"||";
    }
    if (gender.length()%2==0)
    {
        cout<<setw((10-gender.length())/2+gender.length())<<gender<<setw((10-gender.length())/2+2)<<"||";
    }
    else
    {
        cout<<setw((10-gender.length())/2+gender.length())<<gender<<setw((10-gender.length())/2+3)<<"||";
    }
    cout<<setw(9)<<fixed<<setprecision(2)<<price<<"||";
    cout<<setw(10)<<amount<<"||";
    cout<<endl<<"||===========||==========||=========||==========||"<<endl;
}
 
void Zoo::setAll()
{
    cout << "Animal type: "; cin >> type;
    cout << "Gender: "; cin >> gender;
    cout << "Price: "; cin >> price;
    cout << "Amount: "; cin >> amount;
}
 
int main()
{
    cout << "Hello" << endl;
    vector<Zoo> Animal;
    Zoo obj;
    int enter = 0;
    
    do
    {
        obj.Menu();
        cin >> enter;
        switch(enter)
        {
        case 1:
            if (Animal.size() == 0)
            {
                cout << "There is no animals in the shop now." << endl;
            }
            else
            {
                obj.table();
                for (vector<Zoo>::iterator p=Animal.begin();p!=Animal.end(); ++p)
                {
                    p->getAll();
                }
            }
            break;
        case 2:
            obj.setAll();
            Animal.push_back(obj);
            break;
        case 3:
            break;
        }
    }while (enter != 4);
    return 0;
}
Хрисипп
 Аватар для Хрисипп
17 / 27 / 8
Регистрация: 09.02.2016
Сообщений: 212
04.07.2016, 20:07     Вектор объектов класса #4
Цитата Сообщение от zss Посмотреть сообщение
за удалением созданных динамических объектов.
вот у меня в vs15 почему-то вылетает, если в я деструкторе удаляю, а когда не удаляю-все норм. лучше на более старую перейти?
HEYDEPZHUMblU
0 / 0 / 0
Регистрация: 06.06.2016
Сообщений: 18
04.07.2016, 20:18  [ТС]     Вектор объектов класса #5
Я высвобождал память, но это приводило к ещё какой-то ошибке, видимо одна ошибка привела к другой. Убрал код деструктора в коде для того, чтобы не путаться. Сейчас верну.
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11822 / 6801 / 769
Регистрация: 27.09.2012
Сообщений: 16,869
Записей в блоге: 2
Завершенные тесты: 1
04.07.2016, 20:29     Вектор объектов класса #6
Цитата Сообщение от Хрисипп Посмотреть сообщение
вот у меня в vs15 почему-то вылетает, если в я деструкторе удаляю, а когда не удаляю-все норм.
Цитата Сообщение от HEYDEPZHUMblU Посмотреть сообщение
Я высвобождал память, но это приводило к ещё какой-то ошибке, видимо одна ошибка привела к другой.
Всё просто. При удалении одной копии объекта, делается delete в деструкторе,
потом, когда уничтожается другая копия, снова delete и снова для того же адреса.
Хрисипп
 Аватар для Хрисипп
17 / 27 / 8
Регистрация: 09.02.2016
Сообщений: 212
04.07.2016, 20:33     Вектор объектов класса #7
Цитата Сообщение от Croessmah Посмотреть сообщение
Всё просто.
точно. подумал об этом, но не был уверен
Operok
125 / 123 / 33
Регистрация: 15.02.2015
Сообщений: 386
Завершенные тесты: 2
04.07.2016, 22:38     Вектор объектов класса #8
Для использования класса в векторе желательно реализовать копирующие конструктор и оператор присваивания и, так как класс ссылается на какие-то ресурсы (указатели, выделение памяти в куче), то не помешали бы перемещающие конструктор и оператор присваивания. См. правило пяти.
HEYDEPZHUMblU
0 / 0 / 0
Регистрация: 06.06.2016
Сообщений: 18
04.07.2016, 23:28  [ТС]     Вектор объектов класса #9
Спасибо всем. Проблема решилась. Есть ещё пара вопросов. Я написал функцию покупки животных, в ней пользователю предлагается выбрать животное из списка и указать сколько таких животных он хочет купить. 1) Если он вводит число, превышающее количество таких животных, то отображается оповещение об этом; 2) если он вводит число, совпадающее с количеством животных, то строка с этим животным удаляется из таблицы; 3) если он вводит число, меньшее количества таких животных, то количество должно уменьшиться на это число. Вопросы по 2 и 3 пунктам. 2) Если из вектора можно удалить только последний элемент, то одной строкой удалить не получится и придётся вручную делать (как я и сделал) или всё-таки есть способ? Может быть нужно использовать другой контейнер, но я не припомню такого, где можно было бы удалить любой элемент. Мой способ тоже не работает, он работал с массивом объектов класса, но здесь не хочет. 3) Как у элемента вектора объектов класса уменьшить значение одного поля объекта, т.е. количества (в моей программе ничего не происходит, количество остаётся прежним).

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
void Zoo::buy(vector <Zoo> Animal)
{
    if (Animal.size() == 0)
    {
        cout << "There is no animals in the shop now." << endl;
    }
    else
    {
        int enter1, number;
        cout << endl;
        cout << "Enter " << "1" << " to choose an animal." << endl;
        cout << "Enter " << "2" << " to look all the animals." << endl;
        cout << "Enter " << "3" << " to return to the main menu." << endl << endl;
        cin >> enter1;
        switch (enter1)
        {
            case 1:
                cout << "Enter the number of animal which you want to buy" << endl;
                cout << "(enter " << "0" << " to return to the main menu)." << endl << endl;
                cin >> number;
                if (number == 0)
                {
                    break;
                }
                else
                {
                    int k = 0;
                    cout << "How much animals do you want to buy?" << endl;
                    cin >> k;
                    if (k > Animal[number-1].amount)
                    {
                        cout << "There is no " << k << " animals in the shop now.";
                    }
                    else if (k < Animal[number-1].amount)
                    {
                        Animal[number-1].amount-=k;
                        cout << "Thank you for your purchase." << endl;
                    }
                    else
                    {
                        for (unsigned int i = number-1; i < Animal.size()-1; i++)
                        {
                            Animal[i] = Animal[i+1];
                        }
                        cout << "Thank you for your purchase." << endl;
                    }
                }
                break;
            case 2:
                ptr_obj->table();
                for (unsigned int i = 0; i < Animal.size(); i++)
                {
                    Animal[i].getAll();
                }
                break;
        }
    }
}
Добавлено через 5 минут
По поводу деструктора тоже вопрос. Если я не использую динамические переменные, то как высвободить память? Или это нужно только с динамическими переменными?
Operok
125 / 123 / 33
Регистрация: 15.02.2015
Сообщений: 386
Завершенные тесты: 2
05.07.2016, 09:54     Вектор объектов класса #10
Цитата Сообщение от HEYDEPZHUMblU Посмотреть сообщение
По поводу деструктора тоже вопрос. Если я не использую динамические переменные, то как высвободить память? Или это нужно только с динамическими переменными?
Если не используете, то не надо освобождать, почитайте про RAII. Также вы можете не объявлять деструктор без надобности (если вам в нём нечего добавить от себя), тогда компилятор сам сгенерирует необходимые конструкторы, операторы присваивания и деструктор. Так же можно компилятору явно указать:
C++
1
2
3
4
5
6
7
8
9
10
11
class Zoo
{
public:
    ...
    Zoo(const Zoo&) = default;  //конструктор копирования по умолчанию
    Zoo(Zoo&&) = default;  //конструктор перемещения по умолчанию
    Zoo& operator=(const Zoo&) = default;  //копирующий оператор присваивания по умолчанию
    Zoo& operator=(Zoo&&) = default;  //перемещающий оператор присваивания по умолчанию
    ~Zoo() = default;  //деструктор по умолчанию
    ....
}
HEYDEPZHUMblU
0 / 0 / 0
Регистрация: 06.06.2016
Сообщений: 18
05.07.2016, 12:06  [ТС]     Вектор объектов класса #11
Спасибо, а как изменить поля класса? В моей задаче мне нужно изменить количество животных при покупке, но мой код на поле количества не влияет. Почитал про правило пяти, но хотелось бы пример реализации.
Operok
125 / 123 / 33
Регистрация: 15.02.2015
Сообщений: 386
Завершенные тесты: 2
05.07.2016, 13:18     Вектор объектов класса #12
Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от HEYDEPZHUMblU Посмотреть сообщение
В моей задаче мне нужно изменить количество животных при покупке, но мой код на поле количества не влияет.
Т.е. вы вызываете функцию Zoo::buy, покупаете, ещё раз вызываете, выбираете второй пункт меню, а изменение нет? Передавайте вектор по ссылке:
C++
1
2
void Zoo::buy(vector <Zoo> & Animal)
{ ... }
Для вашего случая, если вы отказались от динамических данных, просто не объявляйте деструктор.
Теперь о "правиле пяти"...
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class SomeClass
{
public:
    SomeClass() 
    { 
        init_somedata(data); //инициализация ресурса с помощью некоторой функции (создание объекта в куче через "new" тоже по сути инициализация)
    }  
    ~SomeClass() 
    {
        free_somedata(data); //освободили ресурс (или "delete" для объекта полученного через "new")
    }
 
private:
    SomeDataType* data;  //некоторый ресурс, доступный через указатель
}
Вроде бы всё должно быть хорошо, но если написать нечто такое:
C++
1
2
3
4
5
6
7
8
int main()
{
    SomeClass some_object1;  //ничего страшного
    ...
    {  //некоторая область видимости
        SomeClass some_object2 = some_object1;  //вызов дефолтного конструктора копирования, который просто скопирует указатель
    }
}
После выхода из "некоторой области видимости" второй объект уничтожится (вызовется деструктор) освободив ресурс, на который продолжает ссылаться первый объект.
Для того чтобы избежать таких неприятностей нужно определить копирующие конструктор и оператор присваивания:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class SomeClass
{
   ...
    SomeClass(const SomeClass& other)
    {
        copy_somedata(data, other.data);  //копирование ресурса
    }
    SomeClass& operator=(const SomeClass& other)
    {
        if (&other != this) {   //не нужно присваивать объект самому себе
            free_somedata(data);
            copy_somedata(data, other.data);
        }
        return *this;
    }
    ...
}
На этом можно и остановиться, но с выходом стандарта C++11 мы можем избегать чрезмерного копирование, которое влечёт использование "тяжелых" функций, как наша copy_somedata, если будем использовать семантику перемещения, там где это нужно, разумеется (это очень обширная тема, излагать её тут нет смысла и времени):
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class SomeClass
{
    ...
    SomeClass(SomeClass&& other) noexcept  //перемещающий конструктор не должен бросать исключения
    {
        data = other.data;   
        other.data = NULL;   //other - временный объект и использоваться дальше не будет
    }
    SomeClass& operator=(SomeClass&& other) noexcept
    {
        swap(data, other.data);  //стандартная функция, далее временный объект other будет уничтожен
        return *this;
    }
    ~SomeClass()
    {
        if (data)  //добавим проверку на NULL, так как такая ситуация теперь возможна
            free_somedata(data);
    }
    ...
}
HEYDEPZHUMblU
0 / 0 / 0
Регистрация: 06.06.2016
Сообщений: 18
05.07.2016, 16:39  [ТС]     Вектор объектов класса #13
Спасибо огромное за объяснение. Программа заработала корректно. А почему, когда я передаю вектор по ссылке, всё работает, а иначе ничего не происходит?
Operok
125 / 123 / 33
Регистрация: 15.02.2015
Сообщений: 386
Завершенные тесты: 2
05.07.2016, 16:50     Вектор объектов класса #14
Цитата Сообщение от HEYDEPZHUMblU Посмотреть сообщение
Спасибо огромное за объяснение.
На здоровье.
Цитата Сообщение от HEYDEPZHUMblU Посмотреть сообщение
А почему, когда я передаю вектор по ссылке, всё работает, а иначе ничего не происходит?
Потому что передаёте его по значению (т.е. в функцию передаётся копия вектора, которая уже никак не связана с вашим исхоным вектором, плюс это ещё и накладно по процессорным ресурсам)
HEYDEPZHUMblU
0 / 0 / 0
Регистрация: 06.06.2016
Сообщений: 18
05.07.2016, 20:48  [ТС]     Вектор объектов класса #15
По поводу деструктора тоже вопрос. Задание заключается в реализации класса, в нём должны быть конструкторы (по умолчанию, c параметрами, копирования), деструктор и свои методы. Я ещё не закончил программу, поэтому конструкторы не все. По условию нужен деструктор, но как мне его использовать, если мои переменные не динамические? Я так понимаю, что можно их сделать динамическими, но тогда и дальнейшие действия с ними подкорректировать.
Хрисипп
 Аватар для Хрисипп
17 / 27 / 8
Регистрация: 09.02.2016
Сообщений: 212
05.07.2016, 22:22     Вектор объектов класса #16
Цитата Сообщение от HEYDEPZHUMblU Посмотреть сообщение
По поводу деструктора
а обязательно что-то им делать явно? просто объяви его, да и всё.

Добавлено через 16 минут
ну или ко всему(старому) добавь копирующий конструктор
C++
1
2
3
4
5
6
7
Zoo(const Zoo& z)
{
    type = new string(*(z.type));
    gender = new string(*(z.gender));
    price = new double(*(z.price));
    amount = new int(*(z.amount));
}
ну и конечно в деструкторе delete на каждый
и все будет 0к

Добавлено через 13 минут
и еще одно забыл: также, как и копирующий, определить конструктор перемещения.
C++
1
2
3
4
5
6
7
Zoo(const Zoo&& z)
{
    type = new string(*(z.type));
    gender = new string(*(z.gender));
    price = new double(*(z.price));
    amount = new int(*(z.amount));
}
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
06.07.2016, 09:54     Вектор объектов класса
Еще ссылки по теме:

C++ Не удается корректно создать вектор объектов
Как сортировать вектор объектов по определенному полю? C++
C++ Реализовать подсчет количества объектов класса, используя статическую переменную-член класса

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
HEYDEPZHUMblU
0 / 0 / 0
Регистрация: 06.06.2016
Сообщений: 18
06.07.2016, 09:54  [ТС]     Вектор объектов класса #17
Спасибо, добавлю. С копирующим конструктором и конструктором перемещения пока ещё не очень разобрался, почитаю на эту тему.
Yandex
Объявления
06.07.2016, 09:54     Вектор объектов класса
Ответ Создать тему
Опции темы

Текущее время: 06:32. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru