Search code examples
c++arraysstatic-initializationdatamember

How to initialize static const member that is array of another class, and use it?


I am trying to instantiate a vending machine with in inventory. The inventory I planned to be an array of class Drinks. Here is what I have written so far.

VendingMachine.h - should contain array of Drinks class

#include "Drinks.h"

class VendingMachine {
   private:
      static const int NUM_DRINKS = 5;
      static const Drinks drinks[NUM_DRINKS];
   public:
      VendingMachine();
};

Now Drinks.h

#include <string>

class Drinks {
   private:
      std::string name;
      double price;
      int qtyInMachine;
   public:
      Drinks(std::string name, double price, int qtyInMachine);
      void decrementQuantity();
};

VendingMachine.cpp

#include "VendingMachine.h"

VendingMachine::VendingMachine() {
}

Drinks.cpp

#include <string>
#include "Drinks.h"

Drinks::Drinks(std::string n, double p, int qty) : name(n), price(p), qtyInMachine(qty) {
}
void Drinks::decrementQuantity() {
   qtyInMachine--;
}

Now for test program

#include <iostream>
#include "VendingMachine.h"

const Drinks VendingMachine::drinks[VendingMachine::NUM_DRINKS] {Drinks("Cola",1.25,20),
      Drinks("Root Beer",1.35,20),Drinks("Orange Soda",1.20,20),Drinks("Grape Soda",1.20,20),
      Drinks("Bottled Water",1.55,20)};

int main() {
   VendingMachine vm1;
   for (int i = 0; i < VendingMachine::NUM_DRINKS; i++) {
      std::cout << vm1.drinks[i].name << " ";
   }
}

The line where I define drinks the compiler complains that it is not an integral const-expression and that VendingMachine::NUM_DRINKS is private in the context. It claims the same private context error for my for statement with NUM_DRINKS, also in my cout statement it claims the same for both drinks and name. I need to know how and where to initialize drinks and how to use in main without getting the 'private in this context' errors.

As I am an extreme beginner with classes and OO in general, I cannot find my error. Any assistance is greatly appreciated.


Solution

  • Actually, you need to study / revise the OOP concepts of encapsulation and data-hiding along with the C++ specific features of access specifiers (private and public) and how they're used and in what context.

    Note: There's a protected access specifier also, you'd study it in inheritance topic.

    • public part of a class is visible to the outside world e.g. other classes, functions, etc.
    • private is accessible only within the class itself.

    You have private members that you're accessing in a public context that's why you're getting these errors i.e.:

    class VendingMachine {
       private:
          static const int NUM_DRINKS = 5;          // private to class
          static const Drinks drinks[NUM_DRINKS];   // private to class
       public:
          VendingMachine(){}
    };
    

    and, in main function:

    int main() {
       VendingMachine vm1;
       for (int i = 0; i < VendingMachine::NUM_DRINKS; i++) { // accessing private member VendingMachine::NUM_DRINKS
          std::cout << vm1.drinks[i].name << " ";             // accessing private members vm1.drinks[i].name
       }
    }
    

    The name data member is private to Drinks class and you're accessing it publicly in main.

    These are the issues with that you need to fix.

    For accessing a private data member, usually an accessor function is used such as to access name you'd have a public getName() method and so on.

    • To access private instance data members, you'd need public methods.
    • To access private static data members or class members, you'd need public static member functions.

    Another thing that I'd like to point is this:

    // Declaration: Observe names of the method arguments
    Drinks(std::string name, double price, int qtyInMachine); 
    
    // Definition: Observe the names of the arguments here 
    Drinks::Drinks(std::string n, double p, int qty) : name(n), price(p), qtyInMachine(qty) {
    }
    

    In a separate interface/implementation scenario as it is now, it doesn't matter. But, if you would need to move the definition in the class later you'd have to make them consistent then. So, it's a maintenance overhead in the long run.


    Here's a minimal modified working example: http://ideone.com/tr5oZu