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

Изваждане на поинтер на обект от масив по полета на обекта?

Колеги, кода тук е голямо мазало, за което се извинявам предварително. 

https://github.com/iozzilina/CppHW/blob/master/CashRegister.cpp

Сложих си масив от поинтери към SaleItem-ите, и мога спокойно да си вадя стойностите от полета. Как да препиша for each цикълът, (CheckInventory(string itemID) на пример) за да ми върне поинтера към обекта чиито ид ми трябва, за да мога да го подам на друга функция?

Благодаря предварително.

 

Тагове:
2
C++ Programming
dZf1aeA-rsmarinoff avatar dZf1aeA-rsmarinoff 49 Точки
Best Answer

Когато въртиш цикъл с указатели, просто контролната променлива трябва да ти е указател и нещата са подобни. Имаш си inventory, което в твоя случай, доколкото разбирам е масив от указатели към SaleItem обекти, а не както в дадения код - масив от самите обекти, т.е. при теб предполагам е нещо такова: 

SaleItem* inventory[] =
{
	new SaleItem("aaaaaaaaaa",10.00f),
	new SaleItem("bbbbbbbbbb",10.11f),
	new SaleItem("cccccccccc",10.12f),
	new SaleItem("111111111c",10.13f),
	new SaleItem("222222222b",10.14f),
	new SaleItem("555555555c",10.15f),
	new SaleItem("666666666d",10.16f),
	new SaleItem("777777777e",10.17f),
	new SaleItem("888888888f",10.18f),
	new SaleItem("999999999g",10.19f)
};

Тогава, ще имаш:



SaleItem* getItemById(string itemID)
{
	for(SaleItem* item : inventory)
	{
		if (item->ID == itemID)
		{
			cout << " I found your item and it costs " << item->price << " leva" << endl;
			return item;
		}

		else {
			cout << "Item cannot be found" << endl;
		}
	}
    // If there is no item with the given ID,
    // a new empty item is returned, in order not to return NULL, as it is never good practice.
    return new SaleItem();
}

Тук връщаме указател към някакъв празен айтем, ако не намерим нищо. За тази цел ти трябва някакъв дефаултен конструктор, който да не взима аргументи и такъв предполагам си имаш, съдейки по кода. Отделно те съветвам да си капсулираш полетата в класа, вместо да ги правиш публични. Има различни философии по въпроса, но все пак практиката е да имаш getter-и и setter-и, които достъпват private полета.

0
27/06/2016 15:49:36
iozzilina avatar iozzilina 22 Точки

Хм, сега виждам че и цикъла не върти както трябва..

0
RoYaL avatar RoYaL Trainer 6847 Точки

Не съм сигурен, че for each въобще е от C++ стандарта. Но все пак не трябва ли всеки обект във форийча да е пойнтър, а не копие? Т.е.: for each (SaleItem* item in inventory)

0
dZf1aeA-rsmarinoff avatar dZf1aeA-rsmarinoff 49 Точки

RoYaL

В дадения код в масива има обекти, тъй като са дереференснати със звезда, така че цикълът който се върти там е верен (поправи ме ако греша). Оператори "in" и "each" не бях срещал до сега, може би използва някакъв друг компилатор, не знам. Advanced for loop има в C++ както съм го написал в другия коментар, ползвам го редовно, но мисля че трябва да си поне на C++11.

0
27/06/2016 15:51:11
iozzilina avatar iozzilina 22 Точки

Колеги, благодаря за коментарите. GetItemByID сработи, и съответно мога да по подавам правилно на другите функции и да му сменят стойностите. 

Цикълът все още не върти обаче, и програмата работи само на първия запис от масива...

https://github.com/iozzilina/CppHW/blob/master/CashRegister-01.cpp

+++

GetItemByID за сега я пускам само след булева проверка дали има такъв запис. 

коментарите за публичните полетата ги прочетох. Като подкарам базовата функционалност, и с тях ще се занимая....

0
27/06/2016 16:44:29
dZf1aeA-rsmarinoff avatar dZf1aeA-rsmarinoff 49 Точки

Според мен можеш да минеш и без advanced for loop. Завърти си нормален цикъл с някакъв индекс. 

SaleItem* getItemById(string itemID)
{
    int i = 0;
    int size = sizeof(inventory)/sizeof(inventory[0]);

	for(i=0; i<size; i++)
	{
		if (inventory[i]->ID == itemID)
		{
			return inventory[i];
		}
	}

    return new SaleItem();
}

Тези "each" и "in" оператори са ми яко съмнителни. Напиши я както аз съм я направил в примера, само с "for" и ":" вместо "in", би трябвало също да проработи. Ако нито едно от двете не стане, пали дебъгера и виж точно къде се скапва нещото. Успешно кодене/дебъгване. :D

0
27/06/2016 17:20:20
iozzilina avatar iozzilina 22 Точки

"for each" си работеше :) обаче като сложиш  else : return вътре в цикъла, няма шанс :)

Сега да видим дали ще ми се занимава да оправя гетерите и сетерите :)

Приятен ден!

0
yuletodim avatar yuletodim 37 Точки

Голяма лудница с тия поинтъри, но много удобни. Чак като видях коментарите на колегите към твоя въпрос си оправих бъг, който не знаех как да оправя. Аз ползвам клас Shop, в който с метод addItemToShop(Item &newItem) пъхам продукти в един вектор и после ги ползвам с поинтъри. Предполагам, че някой който повече разбира на някои методи би сложил const, но аз съм още начинаещ :). Ето кода тук. Успех!

0
asparuh.k avatar asparuh.k 16 Точки

В момента гледам кода и мислия че основния проблем е, че изплозваш масив от айтеми, в който искаш да вкараш айтеми, инстанциирани чрез new. new връща пойнтер към айтем, следователно масива трябва да е от пойнтери към айтеми, а не от айтеми. Промени го на SaleItem* inventory[], а вътре използвай new без * . Няма голяма логика да дереференсваш айтемите още при вкарването.

Още по-лошо. Така се получава лийкване на обекти, защото при дереферирането се копира айтема в масива (copy-constructor). Така получаваш два обекта, но адреса на първия не го пазиш никъде. Той седи в хийпа (не в стека) и после не може да освободиш паметта от него. Програмата се грижи за освобождаване на обекти само от стека.

След това за обхождане аз бих използвал като прост вариант for от индекс към масива (малко по-сложния вариант е с итератори).
При обхождането ако ти трябва пойнтера пиши inventory[i]. Ако ти трябва по стойност - *inventory[i] или inventory[i]->price

Не съм прочел внимателно целия код, но се надявам да съм дал някаква посока.

0
28/06/2016 21:08:15