ページ 11

クラスのメンバ変数の値を変更することができません

Posted: 2015年11月07日(土) 01:35
by tapintohigh
掲示板に投稿することが初めてなので、至らぬ点も多々あるかと思いますが、よろしくお願いします。

ItemとItemManagerの2つのクラスを作成し、main関数において、Itemクラスのvectorを作成し、そこにItemManagerクラスのメソッドで要素を追加し、useItem()というメソッドでそれぞれのアイテムのstockを1減らしたいのですが、これができません。

値渡しではなく参照渡しをしているので、できるのかなと思ったのですが、メソッドの中だけでstockが減っているようで、反映はされていません。
この問題は何が原因でどのようにすれば解決できるのでしょうか?

わかりにくい説明でもうしわけございません。
下にコードと実行結果を貼らせていただきます。

<Item.h>

コード:

#pragma once

#include<string>

using namespace std;

class Item{
private:
	int itemNumber;
	int itemStock;
	string itemName;
	string itemType;
	int itemPrice;
	string itemComment;
public:
	Item();
	Item(int iNum, int iS, string iName, string iT, int iP, string iC);
	int getItemNumber() const;
	int &getItemStock();
	string getItemName() const;
	int getItemPrice() const;
};
<Item.cpp>

コード:

#include"Item.h"

Item::Item(){

}

Item::Item(int iNum, int iS, string iName, string iT, int iP, string iC){
	itemNumber = iNum;
	itemStock = iS;
	itemName = iName;
	itemType = iT;
	itemPrice = iP;
	itemComment = iC;
}

int Item::getItemNumber() const {
	return itemNumber;
}

int &Item::getItemStock(){
	return itemStock;
}

string Item::getItemName() const{
	return itemName;
}

int Item::getItemPrice() const {
	return itemPrice;
}
<ItemManager.h>

コード:

#pragma once

#include"Item.h"
#include<vector>
#include<iostream>
#include<algorithm>

using namespace std;

class ItemManager{
	vector<Item> vItem;
public:
	ItemManager();
	void useItem(Item &aItem);
	void addItem(Item &aItem);
	static bool compareTo(const Item &left, const Item &right);
	void sortItem();
	void displayItem();
};
<ItemManager.cpp>

コード:

#include"ItemManager.h"

ItemManager::ItemManager(){
	
}

void ItemManager::useItem(Item &aItem){
	int &stock = aItem.getItemStock();
	stock--;
}

void ItemManager::addItem(Item &aItem){
	vItem.push_back(aItem);
}

bool ItemManager::compareTo(const Item &left, const Item &right){
	if(left.getItemNumber() == right.getItemNumber()){
		return left.getItemName() < right.getItemName();
	}

	return left.getItemNumber() < right.getItemNumber();
}

void ItemManager::sortItem(){
	sort(vItem.begin(), vItem.end(), ItemManager::compareTo);
}

void ItemManager::displayItem(){
	vector<Item>::iterator itr;

	for(auto itr=vItem.begin(); itr!=vItem.end(); itr++){
		cout << itr->getItemNumber() << " " << itr->getItemName() << " " << itr->getItemStock() << endl;
	}
}
<main.cpp>

コード:

#include"ItemManager.h"

int main(){
	ItemManager itemManager;
	vector<Item> vItem;
	
	Item &aItem = Item(3, 2, "Tomato", "Food", 100, "Decayed");
	Item &bItem = Item(2, 1, "Potato", "Food", 120, "Fresh");
	Item &cItem = Item(4, 5, "Onion", "Food", 80, "Fresh");
	Item &dItem = Item(4, 7, "Apple", "Food", 50, "Bitten");

	itemManager.addItem(aItem);
	itemManager.addItem(bItem);
	itemManager.addItem(cItem);
	itemManager.addItem(dItem);

	itemManager.useItem(aItem);
	itemManager.useItem(bItem);
	itemManager.useItem(cItem);
	itemManager.useItem(dItem);
	itemManager.useItem(dItem);

	itemManager.sortItem();
	itemManager.displayItem();
	
	while(1);
	return 0;
}
<実行結果>
2 Potato 1
3 Tomato 2
4 Apple 7
4 Onion 5

よろしくお願いします。

Re: クラスのメンバ変数の値を変更することができません

Posted: 2015年11月07日(土) 05:13
by へにっくす
vector<Item*>じゃなくてvector<Item> と宣言していたらそりゃコピーされるでしょ。ポインタじゃなくなってるし。
つまりmainで宣言しているItemと、itemManagerで保持しているvItemの中身は違うインスタンスになっているのですよ。
試しにItemManager.cppのaddItemを、以下のように変えて実行してみましょうか。

コード:

void ItemManager::addItem(Item &aItem){
    vItem.push_back(aItem); // このときvItemにはaItemとは別のインスタンスを作成し内容をコピーして要素を追加する。
    cout << "add " << std::hex << &aItem << endl; // 追加元のアドレス
    Item &itm = vItem.at(vItem.size() - 1);
    cout << "get " << std::hex << &itm << endl; // 追加された要素のアドレス
}
実行結果

コード:

add 001EF8A8
get 0057FEA8
add 001EF834
get 0057F0B0
add 001EF7C0
get 0057F200
add 001EF74C
get 0057F3B0
2 Potato 1
3 Tomato 2
4 Apple 7
4 Onion 5
addとgetの値が違うだろう?インスタンスが同じならば、同じ値になっていないといけないが、違っているよね。
vector<Item*>に直すか、
あるいはuseItemを以下のように直すかどっちかですね。

コード:

void ItemManager::useItem(Item &aItem){
    vector<Item>::iterator itr;
    // とりあえず名前が一致する要素にアクセスする。 
    for(auto itr=vItem.begin(); itr!=vItem.end(); itr++){
        if (itr->getItemName() == aItem.getItemName()) {
            itr->getItemStock()--;
        }
    }
}

Re: クラスのメンバ変数の値を変更することができません

Posted: 2015年11月07日(土) 06:51
by tapintohigh
へにっくすさん

非常にわかりにく質問であったにもかかわらず、大変わかりやすくかつ丁寧に解説していただき本当にありがとうございました。
無事解決することができました。