Loading...

Във форума е въведено ограничение, което позволява на потребителите единствено да разглеждат публикуваните въпроси.

damyan94 avatar damyan94 9 Точки

Астрономически обекти

Здравейте, опитвам да реша задачата за астрономическите обекти, но срещам някои затруднения. Ще съм благодарен, ако споделите мнения относно подхода, чрез който съм тръгнал да я решавам, и посочените затруднения.

 

Тъй като задачата е малко по-свободна от към това какви функционалности да има, моят подход е да има главен цикъл, който да подканва потребителя какво действие иска да предприеме - създаване на нов запис, промяна на съществуващ или намиране на съществуващ такъв. За целта има един цикъл while със switch конструкция.

 

Затрудненията, които имам засега са следните:

 

    1. Въпреки, че още не съм работил по тази част, подходящ ли е типът изброим за описание на вида обект? Мисля си, че е най-подходящо той да е деклариран глобално, а в класа да има обект от тип ObjType, на който да присвояваме някоя от допустимите стойности. Може ли да имаме обект от тип изброим като аргумент на конструкторите и как може да стане това, понеже за пръв път се сблъсквам с такъв случай, а информацията в интернет, която намирам, не е особено полезна?

 

    2. В case 1 на главната програма искам потребителят да въведе всички задължителни данни за новия обект и ако реши, да въведе и nickname. По този начин написан кодът, програмата винаги очаква въвеждане и на nickname. Как може да се направи така, че ако потребителят напише нов ред на конзолата, въвеждането да спре?

 

    3. В case 3 на главната програма уместно ли е прочитането на данните в паметта директно с главния поток fin >> и как може да се оптимизира така, че да спира да прочита данни в текущия обект, когато достигнем край на реда във файла (предполагам, че това не е толкова сложно, но нещо ми убягва)?

 

    4. В case 3 на главната програма при прочитането на критерии за търсене има същия проблем, както е описано в т. 2 - как при въвеждане на нов ред програмата да спре изпълнението на оператор cin >>?

 

Предварително благодаря за съдействието. Ето го и кодът, който имам до момента:

 

#include <iostream>
#include <fstream>
#include <vector>
using namespace std;

enum ObjType { star, rocky_planet, gas_giant, unknown };
ofstream fout;
ifstream fin;

//class declaration
class AstronomicalObject
{
private:
	string _solarSystem, _nickname;
	int _position;
	float _mass, _radius;
	ObjType _objType;

public:
	AstronomicalObject(string, /*ObjType,*/ int, float, float);
	AstronomicalObject(string, /*ObjType,*/ int, float, float, string);
	void renameObject(string newName) { _nickname = newName; }
	void printObject();
	void writeObject();
	string getSolarSystem() { return _solarSystem; }
	int getPosition() { return _position; }

};

//constructors
AstronomicalObject::AstronomicalObject(string solarSystem, int position, float mass, float radius)
{
	_solarSystem = solarSystem;
	_position = position;
	_mass = mass;
	_radius = radius;
}

AstronomicalObject::AstronomicalObject(string solarSystem, int position, float mass, float radius, string nickname)
{
	_solarSystem = solarSystem;
	_position = position;
	_mass = mass;
	_radius = radius;
	_nickname = nickname;
}

void AstronomicalObject::printObject()
{
	cout << _solarSystem << '-' << _position << " (" << _nickname << ") " << "{mass: " << _mass << ", radius: " << _radius << "}" << endl;
}

//write to file with separator ' '
void AstronomicalObject::writeObject()
{
	fout.open("objects.txt", ios::app);
	if(fout.is_open())
		fout << _solarSystem << ' ' << _position << ' ' << _mass << ' ' << _radius << ' ' << _nickname << endl;
	fout.close();
}

int main()
{
	vector<AstronomicalObject> objects;
	string solarSystem, nickname, searchSolarSystem;
	int position, searchPosition = 0;
	float mass, radius;
	int objType, numObjects = 0, action;
	bool ok = 0;

//main program loop
	while (1)
	{
		cout << "---------------------------------------------\n";
		cout << "Please choose action:\n\n";
		cout << "1. Input new object\n2. Change name of existing object\n3. Print info for existing object\n4. Exit program\n";
		cin >> action;

		switch (action)
		{
		case 1: //input new object
			do
			{
				cout << "Please enter on the same line: solar system, position, mass, radius, nickname(optional)\n";
				cin >> solarSystem >> position >> mass >> radius >> nickname;
				if (nickname == "")
					objects.emplace_back(solarSystem, position, mass, radius);
				else
					objects.emplace_back(solarSystem, position, mass, radius, nickname);
				objects[numObjects].writeObject();
				numObjects++;
			} while (cin.get() != '\n');
			objects.clear();

			break;

		case 2: //change name of object - not started yet
			objects.clear();

			break;

		case 3: //lookup object from file
			
			//open file and read objects to memory
			fin.open("objects.txt", ios::in);
			while (fin.eof())
			{
				fin >> solarSystem >> position >> mass >> radius >> nickname;
				if (nickname == "")
					objects.emplace_back(solarSystem, position, mass, radius);
				else
					objects.emplace_back(solarSystem, position, mass, radius, nickname);
			}
			
			//enter search criteria
			cout << "Please enter on the same line name of solar system and object position(optional)\n";
			do
			{
				cin >> searchSolarSystem >> searchPosition;
			} while (cin.get() != '\n');

			ok = 0;

			//find all objects in given solar system
			if (searchPosition == 0)
			{
				for (int i = 0; i < objects.size(); i++)
					if (objects[i].getSolarSystem() == searchSolarSystem)
					{
						objects[i].printObject();
						ok = 1;
					}
				if (ok == 0)
					cout << "No such solar system exists\n";
				ok = 0;
			}
			
			//find specific object in given solar system
			else
			{
				for (int i = 0; i < objects.size(); i++)
					if (objects[i].getSolarSystem() == searchSolarSystem && objects[i].getPosition())
					{
						objects[i].printObject();
						ok = 1;
					}
				if (ok == 0)
					cout << "No such solar system or object in position exists\n";
				ok = 0;
			}
			fin.close();
			objects.clear();

			break;

		case 4: //exit program
			return 0;
		}
	}
	
	return 0;
}

 

Тагове:
1
C++ OOP 25/07/2021 17:02:31
j.petrov_90 avatar j.petrov_90 373 Точки

Привет, Дамян,
Добре дошъл във форума.

Поздравления за задачата. Смятам, че си се справил блестящо!
Има доста място за подобрения, които ще обсъдим.
Първо да ти отговоря на въпросите.

1. Въпреки, че още не съм работил по тази част, подходящ ли е типът изброим за описание на вида обект?
Абсолютно коректно си използвал enum-а като част от класа.

2. В case 1 на главната програма искам потребителят да въведе всички задължителни данни за новия обект и ако реши, да въведе и nickname. По този начин написан кодът, програмата винаги очаква въвеждане и на nickname. Как може да се направи така, че ако потребителят напише нов ред на конзолата, въвеждането да спре?
Пробвай да въвеждаш цялата информация за обекта на 1 ред. След това прочети реда с getline, зареди го в поток и извличай от там. Така лесно ще разбереш дали имаш nickname или не.

3. В case 3 на главната програма уместно ли е прочитането на данните в паметта директно с главния поток fin >> и как може да се оптимизира така, че да спира да прочита данни в текущия обект, когато достигнем край на реда във файла (предполагам, че това не е толкова сложно, но нещо ми убягва)?
Тук ти си в контрол. В какъвто формат си запишеш файла - в такъв трябва да го прочетеш.
Примерно подсигури си, че всеки запис на 1ца обект във файла ти е на 1 ред и винаги завършва с нов ред.
Така като четещ файла просто правиш, това което говорихме в т.2. getline + stream.


4. Въпрос мисля, че вече успях да ти го отговоря с предишните.

Какво може да се подобри в твоята задача (Имай предвид, че това е advanced критика и я пиша за да ти помогна да се развиеш, а не да ти "търся грешки"). С 2 думи - градивна критика :)

- Супер си се сетил, че може да ползваш enum/enum class за типовете обекти в програмата ти. Направи същото и за опциите на главното меню. case 1, case 2...case 4 не е много четимо.
- Изнеси логиката за "основното меню" в тотално отделен клас. Нека той се грижи за интеракцията с потребителя и предоставя избраната опция на готово.
- Направи клас, който се занимава единствено с писане/четене от файл.
- Направи основен клас, който ще ти фигурира в main функцията. Нека всички останали класове са обекти от този клас. Той ще бъде например class Application.
- да дефинираш нов тип (в случая enum) в глобалния namespace е супер. Да създаваш обекти в глобалния namespace не е ОК.
Стриймовете fout, fin нямат работа там. Можеш спокойно да си ги преместиш като private member-и на класа.
- опитай се да не използваш using namespace std;
- не копирай "тежки" обекти там, където не е нужно. Например std::string не е нужно да го подаваш по value на constructor-а.
Можеш спокойно да го подадеш по константна референция.

Поздрави,
Живко

2
26/07/2021 10:12:09
Можем ли да използваме бисквитки?
Ние използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Можете да се съгласите с всички или част от тях.
Назад
Функционални
Използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Използваме „сесийни“ бисквитки, за да Ви идентифицираме временно. Те се пазят само по време на активната употреба на услугите ни. След излизане от приложението, затваряне на браузъра или мобилното устройство, данните се трият. Използваме бисквитки, за да предоставим опцията „Запомни Ме“, която Ви позволява да използвате нашите услуги без да предоставяте потребителско име и парола. Допълнително е възможно да използваме бисквитки за да съхраняваме различни малки настройки, като избор на езика, позиции на менюта и персонализирано съдържание. Използваме бисквитки и за измерване на маркетинговите ни усилия.
Рекламни
Използваме бисквитки, за да измерваме маркетинг ефективността ни, броене на посещения, както и за проследяването дали дадено електронно писмо е било отворено.