Помогите! Указатели + вектор
Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.
Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.
Всем здравствуйте! Совсем недавно начал изучать язык с++, и наткнулся на такую проблему
Хочу сделать список студентов и сохранить все это в векторе + использую другие классы И потом задать каждому оценки и вывести средний бал. Вот мой код
Student.ccp
student.h
Объясните, пожалуйста, можно ли вектора выражать динамически или какая у меня тут ошибка) А может подход вовсе неверный?
С ошибкой всё просто. Во-первых, необъявленная переменная
student_spisok
. Во-вторых, полагая, чтоstudent_spisok
— это скорее всего векторstring
ФИО студентов, ты вreturn
возвращаешь значение типаstring
. А в сигнатуре метода у тебя указан тип возвращаемого значенияstd::vector<std::string>
. Нестыковочка. Видимо в сигнатуре метода должно бытьstd::string
.Вектора можно делать «динамически». Но в практическом плане обычно это не имеет смысла, так же как и создавать «динамически» переменную под одно число. Вектора, в отличие от массивов, всегда хранят значения в куче. А расход памяти на хранение самой структуры вектора мал, поэтому его проще хранить в стеке. (Это не относится к вектору векторов, если их достаточно много — прямая аналогия с единичным числом и массивом чисел.)
Главная ошибка в твоей программе — это неправильно спроектированный класс. Класс должен представлять атомарную сущность. «Атомарность» определяется текущим уровнем абстракции. Уровни абстракции могут быть представлены по-разному для одной и той же предметной области. Например, может быть такая иерархия абстракций: студент — группа — поток — курс — факультет — ВУЗ. А может быть и такой: студент — ВУЗ. В первом случае студент содержит только сведения об имени (ФИО) и, допустим, оценках; остальные сведения: номер группы, номер потока, номер курса, название факультета будут храниться на других уровнях абстракции. Во втором случае, ВУЗ содержит массив всех студентов, а в каждом студенте есть данные о номере группы, факультете и пр. Но в обоих случаях объект студент — это информация строго по одному учащемуся.
В головной программе ты получаешь от пользователя список имён студентов и сохраняешь его в одном студенте. При этом сам этот студент собственного имени (член
full_name
) не получает. Затем ты планируешь вводить оценки для всех студентов из списка. Но место под оценки ты выделил только для одного набора оценок (в объектеstud
), все остальные «студенты» — это только строки с именами.Из вышесказанного следует, что студент должен содержать данные только о себе, значит поле
std::vector<std::string> students
из объявления убираем. Если нам нужно много студентов, значит делаем контейнер, который может хранить несколько студентов. Контейнером может быть массив, вектор, список и т.п. Конкретный вид контейнера надо выбирать исходя из потребностей.Хорошо, с этим разобрались. Идём дальше: надо привести в порядок набор методов класса. Методы
удаляются однозначно, поскольку относятся к контейнеру, в котором хранятся студенты.
Метод
void set_scores(int[])
вместе сint scores[5]
оставим на совести первоисточника. (Я бы использовал для хранения оценок вектор.)Странно, что для набора оценок есть метод-сеттер, но нет метода-геттера. Ну и ладно, пока он вроде не нужен. Но в уме галочку поставим...
Самый весёлый метод:
void set_averge_ball(float)
. У студента Иванова текущие отметки (scores) двойки и тройки, а мы тут <бах!> вызвалиset_averge_ball
и установили Иванову средний балл 4.88. Да?Одно из правил ООП: данные в объекте должны всегда быть в непротиворечивом состоянии. Метод
void set_averge_ball(float)
нарушает это правило. Средний балл однозначно зависит от оценок, которые содержатся в переменнойscores
. Здесь метод-сеттер противопоказан. А вот метод-геттер — вполне законен.Вычисление среднего балла может быть выполнено двумя способами: либо при добавлении очередной оценки пересчитывается средний балл и запоминается в переменной
float averge_ball
, либо средний балл вычисляется каждый раз, когда вызывается методget_averge_ball
. Хотя более оптимальным будет третий способ: вычислять среднее арифметическое только при первом вызовеget_averge_ball
после любого изменения оценок, а потом возвращать кэшированное значение из переменнойaverge_ball
. Кодить хлопотнее, но производительность будет выше. (В данном случае, конечно, на производительность наплевать, но такие маленькие хитрости всегда надо держать в уме.)Как итог, сделанный на скорую руку в одном файле эскиз программы. (Объявление класса должно быть в отдельном файле, реализации всех методов — тоже должны быть в отдельном файле, как правильно сделано у топикстартера.)
Для интересующихся в качестве бонуса несколько упражнений ;-)
В малый джентльменский набор методов класса я добавил операторы для вывода лога на консоль. Объясните вывод программы.
Можно ли оптимизировать работу с памятью при добавлении студента в группу? Как?
Попробуйте для группы в качестве контейнера использовать массив студентов.
Попробуйте для группы в качестве контейнера использовать массив указателей на студентов.
Воу)
Спасибо большое за такой большой и развернутый ответ. Я пока мало что понял, но надеюсь я дойду до этого) Будем дерзать)