#c #class #random #constructor
#c #класс #Случайный #конструктор
Вопрос:
Я самостоятельно изучаю C по учебнику, и мне нужно решить проблему, описанную ниже.
У меня есть следующая структура класса:
#include <iostream>
#include <cstdio>
#include <ctime>
using namespace std;
class classroom{
char name[25];
int student_id;
float grades[10];
float average;
int num_tests;
float letter_grade;
public:
void enter_name_id(void);
void enter_grade(void);
void average_grades(void);
void letter_grades(void);
void output_name_id_grade(void);
classroom();
};
И у меня есть следующий конструктор для вышеупомянутого класса:
classroom::classroom(){
int i;
srand((unsigned)time(0));
int random_integer=0;
random_integer = (rand()%5) (rand()%5);
num_tests=0;
average=0.0;
for(i=0;i<10;i ){
grades[i]=0.0;
}
for(i=0;i<27;i ){
name[i]='-';
}
cout<<"n*****************Finished*****************";
}
Будет 3 ученика этой структуры класса, объявленной в main
:
int main()
{
classroom students[3];
//and so...
}
Мне нужно сгенерировать уникальный идентификатор учащегося для каждого учащегося в конструкторе в диапазоне значений, скажем, от 0 до 10.
Я скопировал следующий фрагмент кода в конструктор. Он генерирует мое случайное число для меня в пределах желаемого диапазона:
srand((unsigned)time(0));
int random_integer=0;
random_integer = (rand()%5) (rand()%5);
Проблема в том, что мне нужно избавиться от любых дубликатов в пределах диапазона генерируемых случайных чисел.
Комментарии:
1. Исправление: int random_integer=0; следует читать int random_integer;
2. Почему вы 1) используете эту сумму из 2 случайных чисел (которая в принципе не дает вам случайное число в желаемом диапазоне) 2) предполагаете, что случайное число может служить идентификатором?
3. Небольшое замечание: имя класса вводит в заблуждение — объект кажется ближе к
student
, чем кclassroom
. Вам следует подумать о том, чтобы называть свои классы так же, как вы бы их описали — в этом случае они представляют и содержат данные об ученике — поэтому они должны называться примерно такStudent
.4. re: исправление — инициализировать его равным 0, а затем установить его равным чему-то другому, прекрасно и на самом деле является хорошей практикой кодирования.
5. Не уверен, как работает код, как я уже сказал, я просто скопировал его. но, похоже, он делает то, что мне требуется (т. Е. генерирует число от 0 до 10). и я попытался придумать альтернативы моей основной проблеме, но это первое решение, которое я смог придумать.
Ответ №1:
Почему число должно быть случайным? Разве вы не можете просто использовать статический int, который увеличивается каждый раз, когда вам нужно сгенерировать новый номер ученика?
Комментарии:
1. Поскольку закрытые поля в классе доступны только из общедоступных функций-членов, а не непосредственно из основной программы.
2. любое сгенерированное число должно быть перенесено из каждого экземпляра класса. это проще, чем кажется!!!
3. И конструктор при запуске не знает о существовании других экземпляров класса, пока они не будут объявлены в main. в любом случае, я так это вижу. Поэтому я считаю, что это не так просто, как кажется, когда вы изначально сталкиваетесь с этой проблемой.
4. Я полагаю, что jedward упоминал выше статические переменные-члены. это может быть ключом к решению этой проблемы
5. ни одна из этих причин не объясняет, почему идентификатор студента должен быть случайным . Добавьте статическую переменную
static int next_student_id = 0
, затем в вашем конструкторе сделайтеstudent_id = next_student_id
. Затем просто добавьтеget_student_id()
функцию-член, которая возвращает student_id.
Ответ №2:
Просто создайте вектор со всеми возможными идентификаторами учащихся. в вашем случае 0 .. Диапазон.
выполните random_shuffle и выберите первые три идентификатора и назначьте их
Я добавил рабочее решение.
//Only have one instance of this class.
class IdMgr
{
std::vector<int> mIds;
int mCurrentId;
public:
IdMgr( int Max )
{
for ( int i = 0 ; i <= Max; i )
mIds.push_back( i );
std::random_shuffle( mIds.begin() , mIds.end() );
mCurrentId = 0;
}
//Call this function from your class constructor
int GetNextId()
{
return mIds[ mCurrentId ];
}
};
Комментарии:
1. Да, я мог бы это сделать, мне нужно будет посмотреть, как случайная перетасовка работает с вектором. Но будет ли это по-прежнему предотвращать дубликаты??
2. Это предотвратило бы дубликаты, но вы не можете сделать это из конструктора, как вы просите. Это действительно не решает проблему и, вероятно, вводит в заблуждение.
3. Почему это не сработает… Просто сохраните i = 0 как последнее использование идентификатора. Каждый класс может присвоить себе идентификатор в конструкторе из вектора и впоследствии увеличить i. идентификатор будет случайным и также не будет повторяться
4. @Mr_leighman Нет,
random_shuffle
не удаляет повторяющиеся элементы в контейнере. Если вам нужно удалить дубликаты из контейнера, используйте std::unique_copy5. @Mahesh… Как вы думаете, что делает random_shuffle ?
Ответ №3:
Один из способов сделать это — использовать то, что называется статической переменной-членом. Обычно каждый объект получает свою собственную копию переменных-членов. В вашем коде у каждого учащегося будет своя копия name[25]
, student_id
и т.д. Но то, что вы хотите, это то, что будет общим для каждого экземпляра класса (каждый из элементов в classroom students[3]
являются экземплярами classroom
класса.)
Вот несколько заметок о статических переменных-членах. Обратите внимание, что они представляют собой решение очень похожей проблемы — они присваивают уникальные идентификаторы каждому экземпляру класса. Единственное различие между тем, что они представляют здесь, и тем, что вы запрашиваете, заключается в том, что вы просите, чтобы оно было рандомизированным, а не последовательным.
Таким образом, вместо статической переменной-члена, отслеживающей одно число (последнее назначенное), вы захотите, чтобы ваша статическая переменная-член отслеживала все ранее назначенные идентификаторы. Должен работать std.vector или простой массив int.
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <vector>
using namespace std;
class classroom{
char name[25];
int student_id;
float grades[10];
float average;
int num_tests;
float letter_grade;
static vector<int> used;
public:
void enter_name_id(void);
void enter_grade(void);
void average_grades(void);
void letter_grades(void);
void output_name_id_grade(void);
classroom();
};
vector<int> classroom::used = vector<int>();
classroom::classroom(){
int i;
int random_integer=0;
bool rand_ok;
do
{
// Generate Random Integer
random_integer = (rand()%5) (rand()%5);
//cout << "Generated: " << random_integer << endl;
rand_ok = true;
for(i=0; i<used.size(); i )
{
if(used[i] == random_integer){ rand_ok = false; break; }
}
} while (rand_ok == false);
// If we get here, random_integer is not in the used vector
// therefore accept and store as student_id
student_id = random_integer;
// ... and update used vector
used.push_back(student_id);
num_tests=0;
average=0.0;
for(i=0;i<10;i ){
grades[i]=0.0;
}
for(i=0;i<27;i ){
name[i]='-';
}
cout<<"*****************Finished*****************n";
}
int main()
{
// You should only seed the RNG once
srand((unsigned)time(0));
classroom students[3];
}
Приведенный выше код — это один из способов, которым вы могли бы это сделать, сохраняя используемые идентификаторы учащихся в векторе, а затем каждый раз, когда вы создаете нового ученика, убедитесь, что случайно сгенерированный идентификатор не соответствует уже назначенному идентификатору.
Еще одно замечание: вы должны запускать генератор случайных чисел только один раз (особенно если ваше начальное значение — это время). Поскольку вы заполняли его 3 раза за такое короткое время, создаваемые случайные числа были одинаковыми.
Комментарии:
1. Я полагаю, что ваш приведенный выше ответ соответствует тому, что мне нужно. Если мне не нужно генерировать случайные числа и меня устраивают только последовательные числа, я буду просто использовать последовательные числа до тех пор, пока я достигаю своей цели: уникальной идентификации каждого экземпляра класса. Спасибо
2. Предоставленный мной код будет генерировать случайные уникальные числа. Если вам нужны последовательные (также уникальные) числа, вы можете изменить
static vector<int> used;
наstatic int last_used;
, изменитьvector<int> classroom::used = vector<int>();
наint classroom::last_used = 0
и заменить строки 33-53 моего решения наstudent_id = last_used ;
.3. У меня аналогичная настройка, и кажется, что каждый раз, когда я создаю экземпляр своего объекта, я получаю тот же результат. Почему это?
Ответ №4:
Для всех тех, кто хочет знать решение моей проблемы создания уникального идентификатора для каждого экземпляра класса, вот оно:
class classroom{
char name[25];
int student_id;
float grades[10];
float average;
int num_tests;
float letter_grade;
**static int next_student_id;**
public:
void enter_name_id(void);
void enter_grade(void);
void average_grades(void);
void letter_grades(void);
void output_name_id_grade(void);
classroom();
};
**int classroom::next_student_id=1;**
Обратите внимание, что новый элемент: static int next_student_id был создан и использован в конструкторе, он также был инициализирован вне структуры класса.
В конструкторе я просто использовал следующий код:
student_id=next_student_id ;
Этот код создавал уникальные последовательные номера для каждого экземпляра структуры класса classroom;
Пожалуйста, обратите внимание, что я знаю, что Class classroom не является идеальным именем, поскольку оно конфликтует с именем class, но я использовал это, поскольку скопировал базовое название из вопроса учебника!
Я пришел к выводу, что ответ Алана выше помог мне больше всего и предоставил мне самое простое решение.И поэтому Алан получает от меня галочку.
Я хотел бы также поблагодарить Jedwards, ваш ответ, если он будет продолжен, также мог бы быть альтернативным решением… но, как оказалось, использование статического int было ключевым, и генерировать случайные числа и создавать векторы не было необходимости.
И спасибо также парапуре Раджкумару и другим участникам