Полнофункциональная система тестирования

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

angrystrike
Сообщения: 8
Зарегистрирован: 26 июл 2017, 18:52

28 июл 2017, 14:47

Так я вроде и исходил от того чтобы не пришлось писать один и тот же код помногу раз, что конкретно не так?
Absurd
Сообщения: 1213
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

28 июл 2017, 15:45

angrystrike писал(а):Так я вроде и исходил от того чтобы не пришлось писать один и тот же код помногу раз, что конкретно не так?
А что методы get() и delete() делают? Просто по моему метод get() разрушает представления ООП об идентичности объекта, а delete превращает объект в невалидный. То есть после get() у тебя вместо одного объекта получается другой объект, а после delete() у тебя получается объект которого больше нет.

Обычно в ООП создают метод, который может любой объект унаследованный от базового класса записать в поток. Это виртуальный абстрактный метод serialize(std :: ostream& o), который каждый класс реализует по своему. Прочитать объект из потока намного сложнее. Обычно делают так что несколько первых байт которые записал serialize - это метка типа. Тогда при чтении сначала читают метку типа, создают болванку объекта подходящего типа при помощи т.н. фабрики классов, а потом передают этой болванке поток (virtual void read(std :: istream& i) ) чтобы она прочитала все остальное.
2B OR NOT(2B) = FF
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

28 июл 2017, 15:46

Предлагаю писать все данные просто в бинарный поток через write. Каждое поле записывать по правилу: сначала длина, потом чек-сумма, потом шифрованные данные. Поднимаем из файла в таком же порядке.

Небольшие наброски кода. Код писался в блокноте, так что могут быть опечатки.

Код: Выделить всё

#include <string>
#include <fstream>
#include <numeric>
#include <algorithm>
#include <functional>

inline unsigned char CheckSum(const std::string& str)
{
   const auto sum = std::accumulate(str.cbegin(), str.cend(), 0ul);
   // Оставляем только младший байт от всей суммы.
   return static_cast<unsigned char>(sum);
}

void WriteString(std: :o fstream& file, const std::string& str, unsigned char xor_key)
{
   const auto length = str.length();
   file.write(reinterpret_cast<const char*>(&length), sizeof(length));
   const auto check_sum = CheckSum(str);
   file.write(reinterpret_cast<const char*>(&check_sum), sizeof(check_sum));
   char buffer[length];
   std::transform(str.c_str(), str.c_str() + length, buffer, [xor_key](char c){ return (c ^ xor_key); });
   file.write(buffer, length);
}

void ReadString(std::ifstream& file, std::string& str, unsigned char xor_key)
{
   std::size_t length;
   file.read(reinterpret_cast<char*>(&length), sizeof(length));
   unsigned char check_sum;
   file.read(reinterpret_cast<char*>(&check_sum), sizeof(check_sum));
   char buffer[length];
   file.read(buffer, length);
   std::transform(buffer, buffer + length, buffer, [xor_key](char c){ return (c ^ xor_key); });
   str.assign(buffer, buffer + length);
   if (check_sum != CheckSum(str))
   {
      throw MyException();
   }
}

class User
{
   User();
   ~User();

   void Save() const;
   void Load();

private:
   static const unsigned char sm_name_key = 0x13;
   static const unsigned char sm_password_key = 0x57;

private:
   std::string m_file_name;

   std::string m_name;
   std::string m_password;
};

void User::Save() const
{
   std: :o fstream file(m_file_name.c_str(), std::ios_base::binary);
   ::WriteString(file, m_name, sm_name_key);
   ::WriteString(file, m_password, sm_password_key);
}

void User::Load()
{
   std::ifstream file(m_file_name.c_str(), std::ios_base::binary);
   ::ReadString(file, m_name, sm_name_key);
   ::ReadString(file, m_password, sm_password_key);
}
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
angrystrike
Сообщения: 8
Зарегистрирован: 26 июл 2017, 18:52

31 июл 2017, 10:27

На функции read и write string вылазит с десяток ошибок про то что для transform нужно 5 аргументов, а есть 4 и char buffer не инициализируется length, хотя почему если lenght - const, я так и не понял.
У меня VS 2015
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

31 июл 2017, 11:38

1) Глянь тут, transform в первом варианте принимает как раз 4 параметра. Если никак, то перепиши на обычный цикл. Я просто одной строкой хотел сделать.

2) Должно работать на 15-й студии даже если length не константная. Это 11-й стандарт.

В любом случае я сразу предупредил, что это только наброски. Их нельзя взять и вставить, чтобы сразу всё заработало. Их нужно разобрать, понять как это должно работать и потом использоваться у себя не готовый код, а сам подход.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
angrystrike
Сообщения: 8
Зарегистрирован: 26 июл 2017, 18:52

04 авг 2017, 08:30

Ошибка: vector out of range

Код: Выделить всё

vector<Question> quests;
vector<Option> options;

int qAmount;
					cout << "Input quantity of questions, that you want create: ";
					cin >> qAmount;
					quests.resize(qAmount);
					options.resize(qAmount * 4);

					for (int i = 0, j = 0; i < qAmount, j < qAmount * 4; i++, j++)
					{
						quests[i].setData();
						for (int k = 0; k < 4; k++)
						{
							options[j].setQuestName(quests[i].getQuest());
							options[j].setData();
							// ошибка вектор out of range
						}
					}
					ofstream outQ(quests[0].getFile(), ofstream::binary);
					ofstream outO(options[0].getFile(), ofstream::binary);
					if (outQ.is_open() && outO.is_open())
					{
						for (int i = 0; i < qAmount; i++)
						{
							outQ << quests[i].getQuest() << endl;
							outQ << quests[i].getTestName() << endl;
						}
						for (int i = 0; i < qAmount * 4; i++)
						{
							outO << options[i].getOption() << endl;
							outO << options[i].getIsCor() << endl;
							outO << options[i].getQuestName() << endl;
						}
						outQ.close();
						outO.close();
					}
Хочу чтобы спрашивался сам вопрос, в какой тест он входит, далее 4 варианта ответа, всё работает, но при вводе последнего варианта ответа вылазит ошибка
Absurd
Сообщения: 1213
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

04 авг 2017, 21:39

angrystrike писал(а):Ошибка: vector out of range
Ну там в Вижуал Студии можно поставить брейкпоинт и посмотреть в рантайме какого у тебя массив создается размера, куда ты пытаешься записать свой элемент и почему он не влазит. Если у тебя mingw, то можно к нему подключить Eclipse CDT или QtCreator. Какие вообще могут быть проблемы с отладкой однопоточного приложения?
2B OR NOT(2B) = FF
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

05 авг 2017, 01:15

Код: Выделить всё

                    for (int i = 0, j = 0; i < qAmount, j < qAmount * 4; i++, j++)
                    {
                        quests[i].setData();
                        for (int k = 0; k < 4; k++)
                        {
                            options[j].setQuestName(quests[i].getQuest());
                            options[j].setData();
                            // ошибка вектор out of range
                        }
                    }
А кто будет j увеличивать внутри внутреннего цикла?
И условие внешнего цикла неверное. Вот такое выражение

Код: Выделить всё

i < qAmount, j < qAmount * 4;
обозначает "вычислить i < qAmount, результат игнорировать, вычислить j < qAmount * 4, результат вернуть в качестве значения выражения".
То есть, другими словами, выражение с использованием запятых имеет значение последнего операнда.
Если хочешь получить сложное условие, то используй логические операции && и ||, которые обозначают И и ИЛИ соответственно.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Ответить