Thread: How do you overload class constructors?

  1. #16
    Registered User
    Join Date
    Jul 2019
    Posts
    34
    Thank you, I decided to use a map since that seems more like what I want, however the overloading doesnt seem to be working, obviousley i'm doing it wrong. I've been looking up how to get it to work but cant seem to.

    Code:
    #include <iostream>#include <map>
    #include <string>
    #include <iterator>
    
    
    using std::string;
    using std::cout;
    using std::endl;
    using std::map;
    using std::pair;
    
    
    class Character;
    
    
    class Item
    {
    	public:
    		Item(const string& name): m_name(name)
    		{}
    		
    		string GetItemName() const { return m_name; }
    		
    		friend bool operator< (const Item& a, const Character& b)
    		{
    			using pair = std::pair< const string, int >;
    			return pair{ a.GetItemName(), a.GetItemName() } < pair { b.GetItemInventoryAmount(), b.GetItemInventoryAmount() };
    		}
    	
    	private:
    		string m_name{ "Item" };
    };
    
    
    class Character
    {
    	public:
    		Character(const string& name): m_name(name)
    		{}
    		
    		void AddItemToInventory(Item& item, int amountToAdd);
    		void OpenInventory();
    		
    		int GetItemInventoryAmount() const { return m_itemInventoryStock; }
    	
    	private:
    		string m_name{ "Character" };
    		map<Item, int> m_inventory{};
    		int m_itemInventoryStock{ 0 };
    };
    
    
    void Character::AddItemToInventory(Item& item, int amountToAdd)
    {
    	m_inventory.insert(std::make_pair(item, amountToAdd));
    }
    
    
    void Character::OpenInventory()
    {
    	map<Item, int>::iterator it = m_inventory.begin();
    }
    
    
    
    
    int main()
    {
    	Character Link("Link");
    	
    	Item Rupee("Rupee");
    	
    	
    }

  2. #17
    Registered User
    Join Date
    Jul 2019
    Posts
    34
    Ok so i finally got it working, thank you!
    Last edited by ChayHawk; 02-05-2021 at 12:09 PM.

  3. #18
    Registered User
    Join Date
    Jul 2019
    Posts
    34
    Ok so I compiled the code on my chromebook in an android compiler, and i copied it EXACTLY as it was written on my chromebook to Visual studio 2019 on my windows desktop and i'm getting this weird error for some reason. Both VS 2019 and the chromebook app are using c++ 17 standard, so I have no idea why its not working, the error is in here:


    Code:
    void Character::AddToInventory(Item& item, int amount)
    {
        auto iter = inventory.find(item.GetName()); //This line is causing the error
    
    
        if (iter != inventory.end())
        {
            iter->second += amount;
        }
        else
        {
            inventory.emplace(item.GetName(), amount);
        }
    }

    The errors are:


    Code:
    Error    C3536    'iter': cannot be used before it is initialized
    
    
    Error    C2664    'std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const Item,int>>>> std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::find(const Item &)': cannot convert argument 1 from 'std::string' to 'const Item &'    
    
    
    Error    C2677    binary '!=': no global operator found which takes type 'std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const Item,int>>>>' (or there is no acceptable conversion)
    
    
    Error (active)    E0304    no instance of overloaded function "std::map<_Kty, _Ty, _Pr, _Alloc>::find [with _Kty=Item, _Ty=int, _Pr=std::less<Item>, _Alloc=std::allocator<std::pair<const Item, int>>]" matches the argument list
    I must be missing something, The chromebook code compiles in VS but this doesnt, Do I have to put map<Item, int> in the AddToItem function argument list instead of Item& item for this to work?

    I also noticed that the code i compiled on my chromebook, it doesnt exactly work correctly, after adding a few items to it, it will add multiple of the same items to the inventory instead of adding it once and incrementing the amount, but perhaps thats because i didnt use a map like i mentioned above?


    Here is my VS 2019 code:
    Here is the VS 2019 project files if its easier: Basic Inheritance Example


    main.cpp


    Code:
    #include <iostream>
    #include <string>
    #include <tuple>
    
    
    #include "Item Class.h"
    
    
    #include "Weapon Class.h"
    #include "Sword Class.h"
    
    
    #include "Character.h"
    #include "Player.h"
    
    
    int main() 
    {
        //Create our weapons
        Sword MasterSword{ "Master Sword", 1000, 500, 35, 60, 100};
    
    
        //Create our items
        Item Gold("Gold", 1, 1, 1);
        Item WeakPotion("Weak Potion", 40, 25, 2);
    
    
    
    
        Player Link("Link", 100);
        Link.AddToInventory(Gold, 300);
        //Link.AddToInventory(Gold, 30);
        std::cout << Link.GetName() << "'s inventory\n" << std::endl;
        Link.ShowInventory();
    
    
        std::cout << "\n";
    
    
        return 0;
    }

    Character.h


    Code:
    #pragma once
    
    
    #include <iostream>
    #include <map>
    #include <iterator>
    
    
    #include "Item Class.h"
    
    
    using std::map;
    using std::find;
    using std::string;
    using std::cout;
    using std::endl;
    using std::ostream;
    
    
    class Character
    {
        public:
            Character(const string& name, float health) 
                : m_name(name), m_health(health)
            {}
    
    
            string GetName() const { return m_name; }
            float GetHealth() const { return m_health; }
            int GetItemStock() const { return m_itemStock; }
    
    
            friend ostream& operator<<(ostream& os, const Character& character)
            {
                os << "Name: " << character.GetName() << endl;
                //os << "Health: " << character.GetHealth() << endl;
    
    
                return os;
            }
    
    
            void ShowInventory();
            void AddToInventory(Item& item, int amount);
            void RemoveItemFromInventory(Item& item, int amount);
    
    
        private:
            string m_name{ "Character" };
            float m_health{ 100 };
            map<Item, int> inventory{};
            int m_itemStock{ 0 };
    };



    character.cpp


    Code:
    #include "Character.h"
    
    
    void Character::AddToInventory(Item& item, int amount)
    {
        auto iter = inventory.find(item.GetName());
    
    
        if (iter != inventory.end())
        {
            iter->second += amount;
        }
        else
        {
            inventory.emplace(item.GetName(), amount);
        }
    }
    
    
    void Character::ShowInventory()
    {
        map<Item, int>::iterator it = inventory.begin();
    
    
        for (auto& i : inventory)
        {
            std::cout << it->first << " x" << it->second << std::endl;
        }
    }
    
    
    void Character::RemoveItemFromInventory(Item& item, int amount)
    {
        
    }

    player.h


    Code:
    #pragma once
    
    
    #include "Character.h"
    #include "Item Class.h"
    
    
    class Player : public Character
    {
        public:
            Player(const std::string& name, float health)
                : Character{ name, health}
            {}
    };

    weapon class.h


    Code:
    #pragma once
    
    
    #include "Item Class.h"
    
    
    class Weapon : public Item
    {
    public:
        Weapon(const std::string& name, float cost, float value, float weight, float attackPower, float durability)
            : Item{ name, cost, value, weight}, m_attackPower(attackPower), m_durability(durability)
        {}
    
    
        friend std::ostream& operator<<(std::ostream& os, const Weapon& weapon)
        {
            os << static_cast<const Item&>(weapon);
            os << "Attack Power: " << weapon.m_attackPower << std::endl;
            os << "Durability: " << weapon.m_durability << std::endl;
    
    
            return os;
        }
    
    
        float GetAttackPower() const { return m_attackPower; }
        float GetDurability() const { return m_durability; }
    
    
    private:
        float m_attackPower{ 5 };
        float m_durability{ 1 };
    };

    Sword class.h


    Code:
    #pragma once
    
    
    #include "Weapon Class.h"
    
    
    class Sword : public Weapon
    {
        public:
            /*Sword(const std::string& name, float cost, float value, float weight, float attackPower, float durability)
                : Weapon{ name, cost, value, weight, attackPower, durability }
            {}*/
    
    
            //Just inherit weapon constructor since we arent creating any new variables here yet.
            Weapon::Weapon;
    };

    item class.h


    Code:
    #pragma once
    
    
    using std::endl;
    using std::string;
    
    
    class Item
    {
        public:
            Item(const string& name, float cost, float value, float weight)
                : m_name(name), m_cost(cost), m_value(value), m_weight(weight)
            {}
    
    
    
    
            string GetName() const { return m_name; }
            float GetCost() const { return m_cost; }
            float GetValue() const { return m_value; }
            float GetWeight() const { return m_weight; }
    
    
            friend std::ostream& operator<<(std::ostream& os, const Item& item)
            {
                os << item.GetName();
                //os << "Value: " << item.value << std::endl;
                //os << "Weight: " << item.weight << std::endl;
    
    
                return os;
            }
    
    
            friend bool operator<(const Item& a, const Item& b)
            {
                return a.GetName() < b.GetName();
            }
    
    
            friend bool operator==(const Item& l, const Item& r)
            {
                return l.GetName() == r.GetName();
            }
    
    
    
    
        protected:
            string m_name{ "Generic Item" };
            float m_cost{ 2 };
            float m_value{ 1 };
            float m_weight{ 1 };
    };
    Here is the code from the chromebook compile:

    Code:
    #include <iostream>#include <map>
    #include <string>
    #include <iterator>
    
    using std::string;
    using std::cout;
    using std::endl;
    using std::map;
    using std::pair;
    using std::ostream;
    
    class Character;
    
    class Item
    {
    	public:
    		Item(const string& name): m_name(name)
    		{}
    		
    		string GetItemName() const { return m_name; }
    		
    		friend bool operator< (const Item& a, const Item& b)
    		{
    			return a.GetItemName() < b.GetItemName();
    		}
    		
    		friend ostream& operator<<(ostream& os, const Item& item)
    		{
    			os << item.GetItemName();
    			return os;
    		}
    	
    	private:
    		string m_name{ "Item" };
    };
    
    class Character
    {
    	public:
    		Character(const string& name): m_name(name)
    		{}
    		
    		void AddItemToInventory(Item& item, int amountToAdd);
    		void OpenInventory();
    		
    		int GetItemInventoryAmount() const { return m_itemInventoryStock; }
    	
    	private:
    		string m_name{ "Character" };
    		map<Item, int> m_inventory{};
    		int m_itemInventoryStock{ 0 };
    };
    
    void Character::AddItemToInventory(Item& item, int amountToAdd)
    {
    	auto iter = m_inventory.find(item.GetItemName());
    	if(iter != m_inventory.end())
    	{
    		iter->second += amountToAdd;
    	}
    	else
    	{
    		m_inventory.emplace(item.GetItemName(), amountToAdd);
    	}
    }
    
    void Character::OpenInventory()
    {
    	map<Item, int>::iterator it = m_inventory.begin();
    	
    	for(auto& i : m_inventory)
    	{
    		cout <<  it->first << " x" << it->second << endl;
    	}
    }
    
    
    int main()
    {
    	Character Link("Link");
    	
    	Item Rupee("Rupee");
    	
    	Link.AddItemToInventory(Rupee, 5);
    	Link.AddItemToInventory(Rupee, 6);
    	Link.OpenInventory(); }

  4. #19
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,279
    Let's consider this:
    Code:
    map<Item, int> inventory{};
    // ...
    auto iter = inventory.find(item.GetName());
    So, the inventory object maps Item objects to int objects. But you're calling its find member function to find a string. For this to work, there must be an implicit conversion from string to Item, but of course std::string does not have a conversion function that returns an Item, and if we look at the constructors for Item, we don't find a non-explicit one that accepts a std::string argument only.

    What you want to do instead is this:
    Code:
    auto iter = inventory.find(item);
    Now you're directly trying to find an Item object, so what will happen is that the best match for operator< will be used to compare Item objects until the map key matching item is found.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #20
    Registered User
    Join Date
    Jul 2019
    Posts
    34
    OH, ok i totally understand now, thank you. now the last issue i have is a little strange. when I add items to the map, say I do this:

    Link.AddItem(Rupee, 30);
    Link.AddItem(Rupee, 30):

    Then the inventory will only display Rupee x60

    which it should do, thats the behavior I want and expect from it, to just update the amount if the item already exists, however if I add a different item, It will just duplicate the last element pretty much, so if I do this:

    Link.AddItem(Rupee, 30);
    Link.AddItem(Rupee, 30):
    Link.AddItem(Fairy, 4);
    Link.AddItem(Fairy, 6);

    Then it will just output:

    Fairy x10
    Fairy x10

    I'm not understanding why it's doing that. I stepped through it with the debugger and it showed the exact same steps AddItem(Rupee, 6) took, so i'm unsure.

  6. #21
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,279
    I don't see an AddItem member function in the code that you showed previously, so I cannot tell if this is a new function, or if you renamed AddItemToInventory, and if you did, maybe you changed some code thereby introducing a bug.

    In other words, if you have updated your code, you need to show it, otherwise people who are trying to help you are running blind. I probably can write a buggy example that demonstrates the same problem, and someone else could write a different buggy example to demonstrate the same problem, but maybe the bug in your code is a third version, so neither of our advice will be applicable.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #22
    Registered User
    Join Date
    Jul 2019
    Posts
    34
    No the example above is just an example, its not actual code, the result is the same though. If you run the chromebook compile and try to make 2 different items, it will output like that.

    If you run this code you'll see what i mean. Instead of outputting

    Rupee x11
    Fairy x8

    It will just output

    Fairy x8
    Fairy x8

    Code:
    #include <iostream>#include <map>
    #include <string>
    #include <iterator>
    
    
    using std::string;
    using std::cout;
    using std::endl;
    using std::map;
    using std::pair;
    using std::ostream;
    
    
    class Character;
    
    
    class Item
    {
        public:
            Item(const string& name): m_name(name)
            {}
            
            string GetItemName() const { return m_name; }
            
            friend bool operator< (const Item& a, const Item& b)
            {
                return a.GetItemName() < b.GetItemName();
            }
            
            friend ostream& operator<<(ostream& os, const Item& item)
            {
                os << item.GetItemName();
                return os;
            }
        
        private:
            string m_name{ "Item" };
    };
    
    
    class Character
    {
        public:
            Character(const string& name): m_name(name)
            {}
            
            void AddItemToInventory(Item& item, int amountToAdd);
            void OpenInventory();
            
            int GetItemInventoryAmount() const { return m_itemInventoryStock; }
        
        private:
            string m_name{ "Character" };
            map<Item, int> m_inventory{};
            int m_itemInventoryStock{ 0 };
    };
    
    
    void Character::AddItemToInventory(Item& item, int amountToAdd)
    {
        auto iter = m_inventory.find(item);
        if(iter != m_inventory.end())
        {
            iter->second += amountToAdd;
        }
        else
        {
            m_inventory.emplace(item, amountToAdd);
        }
    }
    
    
    void Character::OpenInventory()
    {
        map<Item, int>::iterator it = m_inventory.begin();
        
        for(auto& i : m_inventory)
        {
            cout <<  it->first << " x" << it->second << endl;
        }
    }
    
    
    
    
    int main()
    {
        Character Link("Link");
        
        Item Rupee("Rupee");
        Item Fairy("Fairy");
        
        Link.AddItemToInventory(Rupee, 5);
        Link.AddItemToInventory(Rupee, 6);
        Link.AddItemToInventory(Fairy, 4);
        Link.AddItemToInventory(Fairy, 4);
        Link.OpenInventory(); 
    }
    Last edited by ChayHawk; 02-05-2021 at 10:10 PM.

  8. #23
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,279
    You should compile at a high warning level and pay attention to warnings. For example, my compiler informed me:
    Code:
    test.cpp: In member function ‘void Character::OpenInventory()’:
    test.cpp:78:15: warning: unused variable ‘i’ [-Wunused-variable]
       78 |     for(auto& i : m_inventory)
          |               ^
    So this explains the problem: instead of printing i.first and i.second in the loop, you print it->first and it->second. Since it is set to point to the first element of the map, and it never changes, you always print the first element of the map.
    Last edited by laserlight; 02-05-2021 at 11:18 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #24
    Registered User
    Join Date
    Jul 2019
    Posts
    34
    AH ok, yeah VS never gave me that warning, I probably could have figured that out had it done so. I changed my project to show w4 level warnings but still didnt get any warnings, then tried Wall to show all warnings and still nothing so I'm unsure whats going on. The only warnings i get are telling me some functions can be declared noexcept, but thats it.
    Last edited by ChayHawk; 02-05-2021 at 11:37 PM.

  10. #25
    Registered User
    Join Date
    Sep 2020
    Posts
    62
    VS 2019 16.8.4 gives me this warning with /W4: warning C4189: 'i': local variable is initialized but not referenced
    You probably need to enable Code Analysis on Build under Code Analysis in the project options.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Getting program and overload constructors to work
    By jlin55 in forum C++ Programming
    Replies: 5
    Last Post: 07-07-2017, 11:39 AM
  2. Overload conversion operator from outside class...
    By yaya in forum C++ Programming
    Replies: 4
    Last Post: 08-11-2010, 02:48 PM
  3. Overload == for string class
    By nickname_changed in forum C++ Programming
    Replies: 6
    Last Post: 10-02-2003, 05:07 PM
  4. Replies: 4
    Last Post: 12-29-2002, 12:29 AM
  5. class design and operation overload
    By Unregistered in forum C++ Programming
    Replies: 1
    Last Post: 12-03-2001, 10:49 PM

Tags for this Thread