0

I've submitted an assignment which has met all the criteria except that I'm not allowed to have global variables except if they're constants, and I had my vector set up as a global variable.

I'm now finding it impossible to have my vector used in my header file as well as my class functions file and my main class file.

I have a primary class and a derived class, and the vector items are of the derived class. I've put my vector definition in the header now in the primary class:

vector<Stock> arrStock;

But when trying to add objects into the vector from the input file and subsequently perform actions on it, I am able to either set up the functions inside the classes functions class, OR call the functions I've set up in the main class (if I have the functions set up as static).

What am I doing wrong? Currently with the way the code has been set up, I'm having error E0245 "a nonstatic member reference must be relative to a specific object" on all the functions that I'm calling in my main class. It's probably worth noting that when I had the vector set up as a global variable, the functions were defined as static and they worked perfectly, so I'm open to the fact that they need to be static and that my issue is with the application of the array in the Assignment2_classes.cpp file instead.

Please see my code snippets below:

Assignment2.h:

class Product 
{

private:
    string  title, surname;
    long long int isbn;
    double  wholesalePrice;

public:
    string getTitle();
    string getSurname();
    long long int getIsbn();
    double getWholesalePrice();

    void setTitle(string);
    void setSurname(string);
    void setIsbn(long long int);
    void setWholesalePrice(double);
    
    Product();
    ~Product();
    Product(string, string, long long int, double);

    void importProducts();
    void newProduct();
    void delProduct();
    void runReport();
    void checkStock();
    void clrStock();

    vector<Stock> arrStock;
};

// creating the derived class Stock
class Stock :public Product 
{

public:
    double retailPrice;
    char bookFormat;
    int stockLevel;

    double getRetailPrice();
    char getBookFormat();
    int getStockLevel();
    
    void setRetailPrice(double);
    void setBookFormat(char);
    void setStockLevel(int);

    Stock();
    ~Stock();
    Stock(string, int, char, string, double, long long int, double);
    
    void setStockInfo(long long int, string, string, double, int, double, char);
    
};

Assignment2_classes.cpp:

void Product::importProducts()
{
    // code adapted from: https://stackoverflow.com/questions/16878259/how-to-read-in-a-set-of-values-from-a-text-file-then-go-to-the-next-line-and-do
    // telling the function which input file it is reading from
    ifstream productsFile("products_v5.txt");
    
    // creating local variables
    Stock aStock;
    double tempRetailPrice = 0;
    string undsc = "_";
    string space = " ";
    size_t position;


    std::cout << "Importing books...\n";
    
    // reading the books into an array
    while (productsFile >> aStock.title >> aStock.stockLevel >> aStock.bookFormat >> aStock.surname >> aStock.wholesalePrice >> aStock.isbn)
    {
        // replacing the underscores in the title names with spaces so the output looks better
        // code adapted from https://www.educba.com/c-plus-plus-replace/
        while ((position = aStock.title.find(undsc)) != string::npos)
        {
            aStock.title.replace(position, 1, space);
        }
        
        // calculating the retail prices of the books depending on their format
        switch (aStock.bookFormat)
        {
        case 'a': tempRetailPrice = aStock.wholesalePrice * 1.43;
            break;
        case 'e': tempRetailPrice = aStock.wholesalePrice * 1.08;
            break;
        case 'h': tempRetailPrice = aStock.wholesalePrice * 1.45;
            break;
        case 's': tempRetailPrice = aStock.wholesalePrice * 1.27;
            break;
        }
        aStock.setRetailPrice(tempRetailPrice);
        arrStock.push_back(aStock);
    }

    // letting the user know how many books have been added and how many books are currently in the array
    std::cout << "\n" << to_string(arrStock.size()) << " books have been added.\n";
    std::cout << "\nBiblioden Books currently has " << to_string(arrStock.size()) << " different books.\n";
}

Assignment2_main.cpp:

int main()
{

    char createBook;
    char deleteBook;
    char viewReport;
    char checkOrders;

    // creating the heading of the output
    cout << "-----------------------------------------------------------------------------------------\n" << "  Biblioden Systems\n" << "-----------------------------------------------------------------------------------------\n";
    
    ifstream productsFile("products_v5.txt");
    
    // checking whether the file is open and gracefully exiting if it can't be opened
    if (!productsFile.is_open())
    {
        cout << "\nCannot open file.\n";
        return 1;
    }
    Product::importProducts();
    
    //closing the file
    productsFile.close();
    
    cout << "\nWould you like to enter a new book? (Y/N): ";
    cin >> createBook;
    if (createBook == 'Y' || createBook == 'y')
    {
        Product::newProduct();
    }

    cout << "\nWould you like to delete a book? (Y/N) ";
    cin >> deleteBook;

    if (deleteBook == 'Y' || deleteBook == 'y')
    {
        Product::delProduct();
    }

    cout << "\nWould you like to view a report? (Y/N) ";
    cin >> viewReport;
    if (viewReport == 'Y' || viewReport == 'y')
    {
        ofstream report("report.txt");

        // checking whether the file is open and gracefully exiting if it can't be opened
        if (!report.is_open())
        {
            cout << "\nCannot open file.\n";
            return 1;
        }
        else
        {
            Product::runReport();
            
            // closing the file
            report.close();
        }
    }

    cout << "\nWould you like to check the order list against the stock list? (Y/N) ";
    cin >> checkOrders;
    if (checkOrders == 'Y' || checkOrders == 'y')
    {
        ifstream ordersFile("orders_v5.txt");

        // checking whether the file is open and gracefully exiting if it can't be opened
        if (!ordersFile.is_open())
        {
            cout << "\nCannot open file.\n";
            return 1;
        }
        else
        {
            Product::checkStock();
            // closing the file
            ordersFile.close();
        }
    }

    // clearing out the array once the user is finished with it
    Product::clrStock();
    return 0;
}
  • The calls `MyClass::myFunc();` requires `myFunc()` to be a `static` member of `MyClass` which is not the case here. – Fareanor Nov 17 '21 at 14:59
  • Hi @Fareanor, I'm aware that that's the issue, but how am I actually able to solve it? Should the functions be static , and if so, how do I fix the errors that are thrown up in the Assignment2_classes.cpp file with the vector (the same E0245 error just applied to the vector calling within the functions)? Or should they not be static, and if so how do I fix the error in the Assignment2_main.cpp file? – crab_attack Nov 17 '21 at 15:08
  • Certainly not, I guess you would be interested to read a good C++ book to better understand what `static` does. In your case, you need a proper instance of your class to work on (see my answer). – Fareanor Nov 17 '21 at 15:14
  • Except if you want all possible instances of the class sharing the same unique members (or if you don't want an instance at all and thus a unique vector etc...), then you can make all your members `static` and it should work. – Fareanor Nov 17 '21 at 15:21
  • @Fareanor, I actually do think I want all possible instances of the vector sharing the same unique members... but is that what you're mentioning in the first half of your sentence? – crab_attack Nov 17 '21 at 15:24
  • Well.. actually, if you declare the vector as `static`, then, you'll have one and only one vector shared by all instances of the class (accessible without the need of an instance). – Fareanor Nov 17 '21 at 15:26

2 Answers2

1

As mentioned in comments, the call Product::importProducts(); requires importProducts() to be a static member function of Product.

In your case, you can't declare it as static (and it doesn't make sense to do so) since you use (non-static) class members inside the function.

You need an instance of Product to call the member functions on.
For example:

Product p;          // Create an instance of Product
p.importProducts(); // Call importProducts() from (and for) the previously created instance

On the other hand, if you don't want to create any instance of Product and thus you want a unique vector for the whole program, you may mark your members (and members functions) static to solve your issue.

Fareanor
  • 5,900
  • 2
  • 11
  • 37
  • Oh that does make sense. But I've just re-built the program and apparently there are still 67 errors coming up, at least a few of which are related to the declaration of the base class that yourself and vegalock have been discussing below. I'm having a huge issue wrapping my head around where and I should be declaring my vector, because its objects are members of a derived class rather than a base class. I haven't been able to find anything of that nature in my textbooks. – crab_attack Nov 17 '21 at 15:22
  • @crab_attack I made an edit if you want to make it `static` anyway (i.e. you don't need an instance) – Fareanor Nov 17 '21 at 15:23
  • @crab_attack For the issue related to base class holding derived instances, you need to learn how polymorphism works, it is what you need. – Fareanor Nov 17 '21 at 15:25
  • Hey @Fareanor I have had no luck working out how polymorphism works, all the examples that I've seen have had the vector declared in the main class, which wouldn't work for me because I refer to it in my class functions file. This whole situation seems ridiculous that I've been working on this for literally 5 hours to stop a variable being global, when it worked PERFECTLY with it being global, is there something that I'm missing?? It just seems like it should be a less complicated fix than having literally hundreds of errors thrown up every time I change anything – crab_attack Nov 17 '21 at 15:54
  • @crab_attack You need to read a course about C++ polymorphism because it's a vast topic. I have written a minimal example that uses polymorphism for your use case: [You can see it here](https://godbolt.org/z/MssGr7T8q) – Fareanor Nov 17 '21 at 16:05
0

The declaration of your member variable arrStock comes before the class Stock is declared. You cannot reference a class that has not been declared yet. You have to make your vector as a vector of pointer (or shared_ptr) then you can forward declare the class, before declaring Product, with:

class Stock;
vegalock
  • 51
  • 7
  • Nice hit, but I think having a base class required to know a specific derived of itself is a bad design. OP should better rely on polymorphism instead, it's meant for that. – Fareanor Nov 17 '21 at 15:12
  • I wont argue that point, and the fact that a member variable is public is not recommended either. – vegalock Nov 17 '21 at 15:17