Problem overview
A shop keeps track of how many pieces of each item it has: the item's stock. The stock can never go below 0, and it changes only when pieces are sold or new ones arrive. So the stock is a private field, changed only through two methods that check the rules. The item's name has no rules to protect, so it stays a public field any code can read.
The class InventoryItem has these members:
InventoryItem(name, stock)creates an item with that name and that many pieces in stock.sell(n)sellsnpieces. Ifnis at least 1 and at most the stock, it lowers the stock bynand returnstrue. Otherwise it changes nothing and returnsfalse: selling 0 pieces, a negative number or more than the stock is refused.restock(n)addsnpieces whennis at least 1 and ignoresnotherwise. It returns nothing.getStock()returns the stock, the only way for other code to read it.
For a pencil item with stock 5, sell(3) returns true and leaves 2. Then sell(5) is refused because only 2 are left, and the stock stays 2. After restock(10) it is 12.
Approach
Each method protects the rule "the stock is never negative" by checking its input before changing anything. In sell, the invalid cases are n below 1 and n above the stock; everything else is a valid sale. Checking first and returning early means a refused sale leaves the stock exactly as it was. Note that n equal to the stock is valid: the shop may sell everything it has. In restock, a delivery of 0 or a negative number isn't a delivery, so it is ignored.
Because stock is private, no other code can skip these checks. Every method is a few comparisons, so each runs in constant time.
Step by step
- Declare the stock as
int stock;in theprivate:section. Only the class's own methods can change it. - Declare the name as
string name;in thepublic:section. It has no rule to protect, so other code may read it directly. - Store both parameters in the constructor with
this->name = name;andthis->stock = stock;. The parameters share the fields' names, sothis->picks the fields. - In
sell, refuse what can't be sold. Write anifforn < 1 || n > stockwhose body returnsfalse. The check comes before any change. - Complete the sale. After the
if, subtractnfromstockand returntrue. Only a sale that passed the check gets here, so the stock never goes below 0. - In
restock, addntostockonly whenn >= 1. getStock()returnsstock. Other code can see the number but can never set it.
The solution in C++
class InventoryItem {
private:
int stock;
public:
string name;
InventoryItem(string name, int stock) {
this->name = name;
this->stock = stock;
}
bool sell(int n) {
if (n < 1 || n > stock) {
return false;
}
stock -= n;
return true;
}
void restock(int n) {
if (n >= 1) {
stock += n;
}
}
int getStock() {
return stock;
}
};
A run
This runs the first and third examples. A bool prints as 1 or 0 unless boolalpha is set, so the program turns it on to print true and false.
#include <iostream>
#include <string>
using namespace std;
// the class above goes here
int main() {
cout << boolalpha;
InventoryItem pencil("Pencil", 5);
cout << pencil.name << ": " << pencil.sell(3) << " " << pencil.getStock() << " ";
cout << pencil.sell(5) << " " << pencil.getStock() << " ";
pencil.restock(10);
cout << pencil.getStock() << endl;
InventoryItem lamp("Lamp", 2);
cout << lamp.name << ": " << lamp.sell(0) << " " << lamp.sell(-3) << " ";
lamp.restock(0);
lamp.restock(-5);
cout << lamp.getStock() << " ";
lamp.restock(1);
cout << lamp.sell(3) << " " << lamp.getStock() << endl;
}
It prints:
Pencil: true 2 false 2 12
Lamp: false false 2 true 0
The first line shows a normal sale, then a refused one because only 2 pencils are left, and the stock stays 2 after it. The second line shows the lamps: selling 0, selling -3 and selling 3 of 2 are all refused. The stock is still 2 after restock(0) and restock(-5), which are ignored. Then restock(1) makes it 3, and selling all 3 works and leaves 0.
Details worth knowing
- The order of the two conditions.
n < 1 || n > stockis true if either part is true, so oneifcovers all three refused cases. The||stops as soon as the left side is true, which doesn't matter here but is the usual behaviour. - Private and public together. Members after
private:are hidden and members afterpublic:are open. Herestockis hidden andnameis open. Writingitem.stock = -5from outside the class is a compile error, whileitem.namereads fine. - The return value of
selltells the caller whether the sale happened. Without it the caller would have to compare the stock before and after. restockreturns nothing (void): there is no failure to report, since an invalid delivery is simply ignored.
Common mistakes
- Using
n >= stockas the refusal test. That would refuse selling exactly all the pieces, which the rules allow. - Forgetting the
n < 1part, so selling a negative number would add to the stock. - Subtracting first and checking afterwards. A refused sale must leave the stock unchanged.
- Using
&&instead of||in the refusal test. No number is both below 1 and above the stock, so nothing would ever be refused. - Putting the stock under
public:, which lets other code skip the checks.
