Професионална програма
Loading...
+ Нов въпрос
damyan94 avatar damyan94 3 Точки

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

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

 

Тъй като задачата е малко по-свободна от към това какви функционалности да има, моят подход е да има главен цикъл, който да подканва потребителя какво действие иска да предприеме - създаване на нов запис, промяна на съществуващ или намиране на съществуващ такъв. За целта има един цикъл 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
ditchev avatar ditchev 36 Точки

Здравей, Дамян!

По въпрос 2:

След като прочетеш първите 4 variable пробвай:

if(std::cin.peek()!= '\n')
    std::cin >> nickname;

 

 

PS. това в този случай не върши работа!!!  :((, сори, избързах май, без да размисля ((

даже още по-сигурно е така:

if((std::cin >> std::ws).peek()!='\n)
    std::cin >> nickname;

ако има вероятност да се е промушил някой уайтспейс накрая:))

защото иначе peek() ще го прочете него

 

за да се реши обаче "проблема" с евентуалните спейсове накрая, може да се започне със:

while(std::cin.peek() == ' ')
    std::cin.ignore();

 

1
25/07/2021 22:42:02
j.petrov_90 avatar j.petrov_90 285 Точки

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

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

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
damyan94 avatar damyan94 3 Точки

Много благодаря за помощта, сега задачата е може би на 80 % решена - имаме функционалност за запис, промяна и търсене на обекти. Успях да внедря някои от предложенията, за останалите ще ми трябва малко повече време и да си припомня материала за напреднали. Ето кодът до момента и текстов файл със случайно генерирани обекти:

 

#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>

enum OBJECT_TYPE { STAR, ROCKY_PLANET, GAS_GIANT, UNKNOWN };
enum APP_MENU_OPTIONS {EXIT_APP, ADD_OBJECTS, CHANGE_OBJECT, LOOKUP_OBJECTS };
std::ofstream fout;
std::ifstream fin;

class AstronomicalObject
{
private:
	std::string _solarSystem, _nickname;
	int _position;
	float _mass, _radius;
	OBJECT_TYPE _objType = UNKNOWN;

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

AstronomicalObject::AstronomicalObject(std::string& solarSystem, int position, float mass, float radius, std::string& nickname)
{
	_solarSystem = solarSystem;
	_position = position;
	if (_position == 1)
		_objType = STAR;
	_mass = mass;
	_radius = radius;
	_nickname = nickname;
}

void AstronomicalObject::printObject()
{
	std::cout << _solarSystem << "-" << _position << " (" << _nickname << ") " << "{mass: " << _mass << ", radius: " << _radius << "} ";
	switch (_objType)
	{
	case STAR:
		std::cout << "STAR" << std::endl;
		break;
	case ROCKY_PLANET:
		std::cout << "ROCKY PLANET" << std::endl;
		break;
	case GAS_GIANT:
		std::cout << "GAS GIANT" << std::endl;
		break;
	case UNKNOWN:
		std::cout << "UNKNOWN" << std::endl;
		break;
	}
}

void AstronomicalObject::writeObject()
{
	fout << _solarSystem << ' ' << _position << ' ' << _mass << ' ' << _radius << ' ' << _nickname << std::endl;
}

int main()
{
	std::vector<AstronomicalObject> objects;
	std::string solarSystem, nickname, searchSolarSystem, inputLine;
	int action, position, searchPosition = 0;
	float mass, radius;
	bool ok = 0;
	std::istringstream ss(inputLine);
	ss.clear();

	//read from file to vector of objects in memory
	fin.open("objects.txt", std::ios::in);
	while (!fin.eof())
	{
		//read a line from the file to a string inputLine and read from inputLine to variables
		getline(fin, inputLine, '\n');
		if (inputLine == "")
			continue;
		ss.str(inputLine);
		ss >> solarSystem >> position >> mass >> radius >> nickname;
		ss.clear();

		//create new object at the back of the vector and write the data in it
		objects.emplace_back(solarSystem, position, mass, radius, nickname);
		nickname = "";
	}
	fin.close();

	while (1)
	{
		std::cout << "--------------------------------------------------\n";
		std::cout << "Please choose action:\n\n";
		std::cout << "0. Exit program\n1. Input new objects\n2. Change name of existing object\n3. Print info for existing objects\n";
		std::cin >> action;
		std::cin.ignore();

		switch (action)
		{
		case EXIT_APP:
			//clear the contents of the txt file and write the new data from memory to it
			fout.open("objects.txt");
			if (fout.is_open())
				for (int i = 0; i < objects.size(); i++)
				{
					objects[i].writeObject();
				}
			fout.close();
			objects.clear();
			return 0;

		case ADD_OBJECTS:
			//write to file until the user has input 0
			std::cout << "\nPlease enter on the same line: solar system, position, mass, radius, nickname(optional)\nEnter 0 to stop entering objects\n";
			while (1)
			{
				//read a line from cin that the user has input in inputLine and read from the inputLine to variables in memory, exit loop on 0
				getline(std::cin, inputLine, '\n');
				if (inputLine == "0")
					break;
				if (inputLine == "")
					continue;
				ss.str(inputLine);
				ss >> solarSystem >> position >> mass >> radius >> nickname;
				ss.clear();

				//create new object at the back of the vector
				objects.emplace_back(solarSystem, position, mass, radius, nickname);
				nickname = "";
			}
			break;

		case CHANGE_OBJECT:
			//read a line from cin that the user has input in inputLine and read from the inputLine to variables in memory
			std::cout << "Please enter on the same line name of solar system and object position\n";
			getline(std::cin, inputLine, '\n');
			ss.str(inputLine);
			ss >> searchSolarSystem >> searchPosition;
			ss.clear();

			//rename every object in memory that satisfies the search conditions with the new name provided by the user
			std::cout << "Please enter new name for the object\n";
			getline(std::cin, inputLine, '\n');
			for (int i = 0; i < objects.size(); i++)
				if (objects[i].getSolarSystem() == searchSolarSystem && objects[i].getPosition() == searchPosition)
				{
					objects[i].renameObject(inputLine);
					ok = 1;
				}
			searchPosition = 0;
			if (ok == 0)
				std::cout << "No such solar system or object in position exists\n";
			ok = 0;
			break;

		case LOOKUP_OBJECTS:
			//read variables from cin that the user has input
			std::cout << "Please enter on the same line name of solar system and object position(optional)\n";
			std::cin >> searchSolarSystem;
			if (std::cin.peek() != '\n')
				std::cin >> searchPosition;

			//based on user input show the objects that satisfy the search conditions
			ok = 0;
			std::cout << "--------------------------------------------------" << std::endl;

			//if the user has input only solar system name, show everything in the 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)
					std::cout << "No such solar system exists\n";
				ok = 0;
			}

			//if the user has input solar system name and position, only show the required object
			else
			{
				for (int i = 0; i < objects.size(); i++)
					if (objects[i].getSolarSystem() == searchSolarSystem && objects[i].getPosition() == searchPosition)
					{
						objects[i].printObject();
						ok = 1;
					}
				searchPosition = 0;
				if (ok == 0)
					std::cout << "No such solar system or object in position exists\n";
				ok = 0;
			}
			break;
		}
	}

	return 0;
}

 

0