0

I want to make a dynamic menu in which it detects whether you have one or more durability in your inventory. If you do have one or more, it prints out into the menu. Otherwise, it won't.

Here's the code:

#include <iostream>
#include <vector>
using namespace std;
class A {
protected:
    int durability = 3;
public:
    virtual void attack() { };
    virtual int usage() { return 1; };
    virtual string weaponName() { return "Sword x"; };
};
class B : public A
{

public:
    void attack() { durability--; cout << "B Attack" << endl; cout << durability; };
    string weaponName() { return "Sword B"; };

};
class C : public A
{
public:
    int usage() { return durability; };
    void attack() { durability--; cout << "C Attack" << endl;cout << durability; };
    string weaponName() { return "Sword C"; };
};
class D : public A
{

public:
    void attack() { durability--;  cout << "D Attack" << endl;cout << durability; };
    string weaponName() { return "Sword D"; };
};
int main(void)
{
B * b = new B;
C * c = new C;
D * d = new D;
    int k = 10;
    vector <A*> tableOfAs;
    tableOfAs.push_back(b);
    tableOfAs.push_back(c);
    tableOfAs.push_back(d);
    while (--k>0)
    {
        int i = 0;
        vector <A*> options;
        for (i = 0; i < tableOfAs.size(); i++)
        {
            if (tableOfAs[i]->usage() > 0){
                options.push_back(tableOfAs[i]);
        } else { delete tableOfAs[i]; }
        }
        if (options.size() == 0)
            break;
        cout << "Attack Options:" << endl;
            for (i = 0; i < options.size(); i++)
            cout << i << ". " << options[i]->weaponName().c_str() << endl;
        int choise;
        cin >> choise;
        if (choise<0 || choise > options.size()-1)
            cout << "Wrong option" << endl;
        else
            options[choise]->attack();
    }
    return 1;
}

My problem here is that the durability gets zeroed and gets deleted and then after placing another choice, the console crashes.

CraftedGaming
  • 499
  • 7
  • 21
  • What is the question? Please take [the tour](http://stackoverflow.com/tour) and read the [help page](http://stackoverflow.com/help). Here is a nice list of [C++ books](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). –  Jan 10 '17 at 14:58
  • When you used the **debugger**, which statement is causing the issue? What are the actual values of the variables? What are the expected values of the variables? Please edit your post with the answers. – Thomas Matthews Jan 10 '17 at 15:18
  • @RawN I made the question bold so that you and others can see it – CraftedGaming Jan 11 '17 at 03:42
  • @ThomasMatthews There's no error shown but it selects the sword based on the code and not on the menu. – CraftedGaming Jan 11 '17 at 03:42
  • @TobySpeight I updated the code – CraftedGaming Jan 11 '17 at 03:42

2 Answers2

2

Try a different approach Create a parent class weapon that has some pure virtual functions.

  • weaponName()

  • usage()

  • attack()

then create classes that inherit these from the weapon class, and implement accordingly.

Do the checks using the usage method, if the result is > 0 then add it to the table of pointers of class weapon. Then use the weaponName function to print the names during the listing of options, and then upon selection use the attack() method from the object that is in the index of the table. So if stick_sword is in index 1 of the table and you call weaponInv[1].attack() it will call the stick_sword attack.

Here is a simple demonstration of the suggested logic:

Updated:

#include <iostream>
#include <vector>

class A {
public:
    virtual void attack() {};
    virtual int usage() { return 1; };
    virtual std::string weaponName() { return "Sword x"; };
};
class B : public A
{
public:
    void attack() { std::cout << "B Attack" << std::endl; };
    std::string weaponName() { return "Sword B"; };

};
class C : public A
{
private:
    int durability;

public:
    C() :durability(3) {};
    int usage() { return durability; };
    void attack() { durability--; std::cout << "C Attack" << std::endl; };
    std::string weaponName() { return "Sword C"; };
};
class D : public A
{
public:
    void attack() { std::cout << "D Attack" << std::endl; };
    std::string weaponName() { return "Sword D"; };
};
int main(void)
{
    B b;
    C c;
    D d;
    int k = 10;
    std::vector <A*> tableOfAs;
    tableOfAs.push_back(&b);
    tableOfAs.push_back(&c);
    tableOfAs.push_back(&d);
    while(--k>0)
    {
        int i = 0;
        std::vector <A*> options;
        for (i = 0; i < tableOfAs.size(); i++)
        {
            if (tableOfAs[i]->usage() > 0)
                options.push_back(tableOfAs[i]);
        }
        if (options.size() == 0)
            break;
        std::cout << "Attack Options:" << std::endl;
        for (i = 0; i < options.size(); i++)
            std::cout << i << ". " << options[i]->weaponName().c_str() << std::endl;
        int choise;
        std::cin >> choise;
        if (choise<0 || choise > options.size() - 1)
            std::cout << "Wrong option" << std::endl;
        else
            options[choise]->attack();
    }
    return 1;
}
boring32
  • 136
  • 4
  • I don't see how this is applicable in my case. I could see you tried to pass the objects using an array but how can I make my choices dynamic? – CraftedGaming Jan 12 '17 at 06:55
  • This almost solves my problem but Sword C disappears regardless if you use it or not on the 4th loop. – CraftedGaming Jan 13 '17 at 11:12
  • I tried your code and it makes the object "C" stay but I updated my code above to check what the durability is. I looked up on the internet on how to destroy an object when it's variable reaches zero. I know it has something to do with pointers but I don't know how to do it as I'm still new to the language. Also your summary above your code is incorrect. – CraftedGaming Jan 14 '17 at 04:30
  • @CraftedGaming the objects are created in main scope so they will destroyed after the main function exits. If you want to control when an object is created and destroyed, use a pointer and the new operator to create a new instance of the object. Then use delete to destroy it. – boring32 Jan 17 '17 at 09:56
  • I updated my code. It manages to delete it but my console crashes after I input another choice once one of the object gets deleted. – CraftedGaming Jan 18 '17 at 04:12
  • It sounds like the first table that contains all the weapons is left with a dazzling pointer. – boring32 Jan 18 '17 at 15:07
0

Looking back at this old post. I revised the code from boring32. I made it a lot easier to read for those new to programming.

#include <iostream>
#include <string>
#include <vector>
using namespace std;
class baseClass {
public:
    virtual void attack() {};
    virtual int usage() { return 1; }
    virtual string weaponName() { return "Sword x"; }
};
class Sword : public baseClass
{
private:
    int durability;
    string name;
public:
    /*Sets the name and the durability of the sword*/
    Sword(string nameToSet, int dur) :name(nameToSet),durability(dur) {}
    int usage() { return durability; }
    /*Decreases durability by one and tells the name of the sword used in the attack*/
    void attack() { 
        durability--; 
        cout << name <<" Sword Attack" << endl;
    }
    /*returns weapon name*/
    string weaponName() { return name +" Sword"; }
};
int main()
{
    Sword sworda("One", 1), swordb("Two", 2), swordc("Three", 3);
    int loop = 10;
    int choice;
    /*Add swords into a holding container first*/
    vector <baseClass*> holdingContainer;
    holdingContainer.push_back(&sworda);
    holdingContainer.push_back(&swordb);
    holdingContainer.push_back(&swordc);

    while (--loop>0)
    {
        /*Decide whether swords in the holding container has a durability of one or more
          before adding them into the menu*/
        vector <baseClass*> swordWithDurabilityContainer;
        for (int i = 0; i < holdingContainer.size(); i++)
        {
            if (holdingContainer[i]->usage() > 0) {
                swordWithDurabilityContainer.push_back(holdingContainer[i]);
            }
        }

        /*Check if there's any items in the swordWithDurabilityContainer otherwise break out of the loop*/
        if (swordWithDurabilityContainer.size() == 0) { break; }

        /*Print the items*/
        cout << "Attack Options:" << endl;
        for (int i = 0; i < swordWithDurabilityContainer.size(); i++) {
            cout << i << ". " << swordWithDurabilityContainer[i]->weaponName().c_str() << endl;
        }
        /*Ask for user input*/
        cin >> choice;

        /*Check if the input is valid*/
        if (choice<0 || choice > swordWithDurabilityContainer.size() - 1) {
            cout << "Wrong option" << endl;
        }
        else {
            swordWithDurabilityContainer[choice]->attack();
        }
    }
    /*Notify the user that the loop has ended*/
    cout << "No more items in the list(swordWithDurabilityContainer variable)";
}

Back then when I was reading boring32's answer, I couldn't read it because there are barely any comments and variables named as "a", "b" and Classes named "A", "B" and classes which have no correlation with the code. I came back to fix it. Although I'm not sure why some people make it a habit to leave a semi-working code in forums/threads.

No offense to those who also do this.

CraftedGaming
  • 499
  • 7
  • 21
  • Thank for your feedback, I will try in the future to provide answers that are easier to read. Initially I was trying to demonstrate how to use pointers and polymorphism to achieve the dynamic menu that you wanted, and then through your questions I made small modifications to adjust it to your example. Therefore the A B C classes and names remained the same. Glad that you managed to get it working though :) – boring32 Jul 31 '17 at 09:33