Explain how this works

Hi,

I have been reading C++ Primer 5th Edition and I am stuck on Exercise 1.23. I found the code solution online but I do not understand how this works. Can anyone explain please.

Exercise 1.23: Write a program that reads several transactions and counts how many transactions occur for each ISBN.

Things I don't understand is
- Why two variable ?
- What is if (cin >> currItem) doing ?
- What is while (cin >> sum) doing ?
- What these two are doing in else statement after the output ?
currItem = sum;
count = 1;
- what's this doing in if statement ?
cout << currItem << " occurs "<< count << " times " << endl;

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include "Sales_item.h"

using namespace std;

int main()
{
   Sales_item currItem, sum;
   if (cin >> currItem)
   {
       int count = 1;
       while (cin >> sum)
       {
           if (currItem.isbn() == sum.isbn())
           {
               count++;
           }
           else
           {
               cout << currItem.isbn() << "occurs " << count << " times. " << endl;
               currItem = sum;
               count = 1;
           }
       }
       cout << currItem << " occurs "<< count << " times " << endl;
   }
   return 0;
}


Sales_item.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

#ifndef SALESITEM_H
// we're here only if SALESITEM_H has not yet been defined
#define SALESITEM_H

// Definition of Sales_item class and related functions goes here
#include <iostream>
#include <string>

class Sales_item {
// these declarations are explained section 7.2.1, p. 270
// and in chapter 14, pages 557, 558, 561
friend std::istream& operator>>(std::istream&, Sales_item&);
friend std::ostream& operator<<(std::ostream&, const Sales_item&);
friend bool operator<(const Sales_item&, const Sales_item&);
friend bool
operator==(const Sales_item&, const Sales_item&);
public:
    // constructors are explained in section 7.1.4, pages 262 - 265
    // default constructor needed to initialize members of built-in type
    Sales_item() = default;
    Sales_item(const std::string &book): bookNo(book) { }
    Sales_item(std::istream &is) { is >> *this; }
public:
    // operations on Sales_item objects
    // member binary operator: left-hand operand bound to implicit this pointer
    Sales_item& operator+=(const Sales_item&);

    // operations on Sales_item objects
    std::string isbn() const { return bookNo; }
    double avg_price() const;
// private members as before
private:
    std::string bookNo;      // implicitly initialized to the empty string
    unsigned units_sold = 0; // explicitly initialized
    double revenue = 0.0;
};

// used in chapter 10
inline
bool compareIsbn(const Sales_item &lhs, const Sales_item &rhs)
{ return lhs.isbn() == rhs.isbn(); }

// nonmember binary operator: must declare a parameter for each operand
Sales_item operator+(const Sales_item&, const Sales_item&);

inline bool
operator==(const Sales_item &lhs, const Sales_item &rhs)
{
    // must be made a friend of Sales_item
    return lhs.units_sold == rhs.units_sold &&
           lhs.revenue == rhs.revenue &&
           lhs.isbn() == rhs.isbn();
}

inline bool
operator!=(const Sales_item &lhs, const Sales_item &rhs)
{
    return !(lhs == rhs); // != defined in terms of operator==
}

// assumes that both objects refer to the same ISBN
Sales_item& Sales_item::operator+=(const Sales_item& rhs)
{
    units_sold += rhs.units_sold;
    revenue += rhs.revenue;
    return *this;
}

// assumes that both objects refer to the same ISBN
Sales_item
operator+(const Sales_item& lhs, const Sales_item& rhs)
{
    Sales_item ret(lhs);  // copy (|lhs|) into a local object that we'll return
    ret += rhs;           // add in the contents of (|rhs|)
    return ret;           // return (|ret|) by value
}

std::istream&
operator>>(std::istream& in, Sales_item& s)
{
    double price;
    in >> s.bookNo >> s.units_sold >> price;
    // check that the inputs succeeded
    if (in)
        s.revenue = s.units_sold * price;
    else
        s = Sales_item();  // input failed: reset object to default state
    return in;
}

std::ostream&
operator<<(std::ostream& out, const Sales_item& s)
{
    out << s.isbn() << " " << s.units_sold << " "
        << s.revenue << " " << s.avg_price();
    return out;
}

double Sales_item::avg_price() const
{
    if (units_sold)
        return revenue/units_sold;
    else
        return 0;
}
#endif
Last edited on
This might help?

I commented out just your main.cpp code with out looking at your custom class,
because I am tired and we really should not have to look at the implementation of the class to know how it works.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include "Sales_item.h"

using namespace std;

int main()
{
    // creating to objects currItem, sum of Sales_item
    Sales_item currItem, sum;
    
    // if cin (common input) is reading a object of Sales_item.
    if (cin >> currItem)
    {
        // set count to one
        int count = 1;
        // while cin is reading an input
        while (cin >> sum)
        {    // if currITem.sum and sum.isbn are identical. 
            if (currItem.isbn() == sum.isbn())
            {
                // increment count by one
                count++;
            }
            else
            {
                // print current item isbn and count times.
                cout << currItem.isbn() << "occurs " << count << " times. " << endl;
                // set currentItem = to sum {with out looking at Sales_item.h we will assume
                // this is correct. 
                currItem = sum;
                // set count to on
                count = 1;
            }
            // check while condition above or end loop.
        }
        // print current item and count. 
        cout << currItem << " occurs "<< count << " times " << endl;
    }
    return 0;
}
Thanks bro. I am still confused about

1
2
3
4
5
// set currentItem = to sum {with out looking at Sales_item.h we will assume
// this is correct.
currItem = sum;
// set count to on
count = 1;


Why are we setting currentItem = sum and setting count to 1 ?
What do you think?
Also confused about two similar output statement and both are printing the same thing as your comment says

// print current item and count.
I suppose context is king. What is the program trying to accomplish from your perspective?
To be honest I am lost but according to question it is reading several transactions and counts how many transactions occur for each ISBN.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <iostream>
#include "Sales_item.h"

using namespace std;

int main()
{
   Sales_item currItem, sum; // created 2 objects of type Sales_item, 
   	   	   	   	   	   	   	 // one called currItem and one called sum 
   if (cin >> currItem) // try to read a Sales_item object 
	   	   	   	   	   	// into the variable currItem. 
	   	   	   	   	    // If successful, execute the if body
   {
	   // We have successfully read a Sales_item object into currItem.
	   
       int count = 1; 	   // Our objective, is to count 
       	   	   	   	   	   // the number of Sales_item objects 
       	   	   	   	   	   // that have the same isbn so we create 
       	   	   	   	   	   // a variable called count.
       	   	   	   	   	   // We initialise count to 1 because we already
       	   	   	   	   	   // have our first Sales_item object  
 
       while (cin >> sum) // try to read a Sales_item object into 
    	   	   	   	      // the variable sum. If successful, execute 
    	   	   	   	   	  // the body of the while loop and try again
       {
    	   // We have successfully read a Sales_item object into currItem.
    	   // Now we have 2 Sales_item objects, in sum and currItem
    	   
           if (currItem.isbn() == sum.isbn()) // compare the isbn of sum 
        	   	   	   	   	   	   	   	   	  // and currItem, execute
        	   	   	   	   	   	   	   	   	  // the body of the if block 
        	   	   	   	   	   	   	   	   	  // if they are the same 
        	   	   	   
           {
        	   // sum and currItem have the same isbn, so we increment count.
        	   // That means the first time we pass through this loop we have
        	   // 2 books with the same isbn - each time through the loop
        	   // we will have count books with the same isbn after the next line.
               count++;
           }
           else
           {
        	   // The isbn are different. Since the books are grouped by isbn, 
        	   // we can safely say we only have count number of books that have 
        	   // the same isbn as currentItem
        	   // 
               cout << currItem.isbn() << "occurs " << count << " times. " << endl;
               
               // sum now contains the new book that has a different isbn, 
               // and we now have to count the number of books that have that 
               // same isbn
               // To continue using our code as before, our new currentItem 
               // must now be set to the value in sum, and the count is set to 1
               // since we have only that 1 book with that isbn
               // notice that this was the same condition as we were in at the 
               // start of the loop,  
               currItem = sum;
               count = 1;
           }
       }
       
       // we have failed to read in the next book, which means there are no more 
       // books. Let's print the number of copies of the last (currentItem) book.
       cout << currItem << " occurs "<< count << " times " << endl;
   }
   
   // We have either finished, in which case the messages above were printed
   // or we failed at the first book, in which case there are no books.
   return 0;
}
Topic archived. No new replies allowed.