Learing cpp from books

Hi,
I have been reading Primer Plus by Stephen Prata, I have reached end of 14 chapter (which is mainly about class templates). Now I found out that Prata's book is rather not recommended.
If I would want to read something else (I'm thinking about Programming: Principles and Practice Using C++ or C++ Primer (Stanley Lippman, Josée Lajoie, and Barbara E. Moo)) where should I start reading? From the scratch?

P.S. English is not my native language, but I hope text above is understandable. I'm sorry if I made some mistakes.
I don't have an answer but I recognize those authors and they have produced excellent work in the past.

My first thought is to check the publication date on anything you consider. If it is more than 5 years old, it is too old to use. Ideally it would be even more recent, covering through c++ 17. There are many thousands of old books out there and its easy to forget to look at the age when shopping.

Our C++ course uses C++ Primer as reference literature and C++ How to program 8th edition by Dietel as course book.

But i find Programming: Principles and Practice Using C++ 2nd edition very useful and it is now my new reference.
Last edited on
> where should I start reading? From the scratch?

Ideally, yes.

Since you had already reached chapter 14 of the other book, it would take less time now.
But do read the whole book from the beginning, and try out the exercises at the end of each chapter/section.
Thank you for answers. I wanted to avoid going over the basics, but JLBorges have a point, it shouldn't take long.

I also wanted to ask about exercise from Primer Plus.
There are some questions about this exercise in the Internet and I know it is bad idea to use Pair template (instead of pair) or valarray template, but I still want to ask some questions.

Task:
The Wine class has a string class object member (see Chapter 4) that holds the
name of a wine and a Pair object (as discussed in this chapter) of valarray<int>
objects
(as discussed in this chapter).The first member of each Pair object holds
the vintage years, and the second member holds the numbers of bottles owned for
the corresponding particular vintage year.
For example, the first valarray object of
the Pair object might hold the years 1988, 1992, and 1996, and the second
valarray object might hold the bottle counts 24, 48, and 144. It may be convenient
for Wine to have an int member that stores the number of years.Also some
typedefs might be useful to simplify the coding:

typedef std::valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArray;

Thus, the PairArray type represents type Pair<std::valarray<int>,
std::valarray<int> >.
Implement the Wine class by using containment.The class
should have a default constructor and at least the following constructors:

// initialize label to l, number of years to y,
// vintage years to yr[], bottles to bot[]
Wine(const char * l, int y, const int yr[], const int bot[]);
// initialize label to l, number of years to y,
// create array objects of length y
Wine(const char * l, int y);

The Wine class should have a method GetBottles() that, given a Wine object with
y years, prompts the user to enter the corresponding number of vintage years and
bottle counts.A method Label() should return a reference to the wine name.A
method sum() should return the total number of bottles in the second
valarray<int> object in the Pair object.

The program should prompt the user to enter a wine name, the number of elements
of the array, and the year and bottle count information for each array element.
The program should use this data to construct a Wine object and then display
the information stored in the object. For guidance, here’s a sample test program:

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
#include <iostream>
#include "wine.h"
int main ( void )
{
 using std::cin;
 using std::cout;
 using std::endl;

 cout << "Enter name of wine: ";
 char lab[50];
 cin.getline(lab, 50);
 cout << "Enter number of years: ";
 int yrs;
 cin >> yrs;

 Wine holding(lab, yrs); // store label, years, give arrays yrs elements
 holding.GetBottles(); // solicit input for year, bottle count
 holding.Show(); // display object contents
 const int YRS = 3;
 int y[YRS] = {1993, 1995, 1998};
 int b[YRS] = { 48, 60, 72};
// create new object, initialize using data in arrays y and b
 Wine more("Gushing Grape Red",YRS, y, b);
 more.Show();
 cout << "Total bottles for " << more.Label() // use Label() method
 << ": " << more.sum() << endl; // use sum() method
 cout << "Bye\n";

 return 0;
}


Here is my solution:
wine.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
#ifndef WINE_H_
#define WINE_H_

#include <iostream>
#include <valarray>

// Pair class template [copied]
template <typename T1, typename T2> // changed class T to typename T
class Pair
{
private:
    T1 a;
    T2 b;

public:
    T1 & first();
    T2 & second();
    T1 first() const { return a; }
    T2 second() const { return b; }
    Pair(const T1 & aval, const T2 & bval) : a(aval), b(bval) { }
    Pair() {}
};

// Pair class template methods
template <typename T1, typename T2>
T1 & Pair<T1, T2>::first()
{
    return a;
}

template <typename T1, typename T2>
T2 & Pair<T1, T2>::second()
{
    return b;
}

// Wine class
// typedef
typedef std::valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArray;

class Wine
{
private:
    std::string label;
    int years;
    PairArray yearAndBAmt; // => Pair<std::valarray<int>, std::valarray<int> >

public:
    // constructors
    // default
    Wine() : label("none"), years(0), yearAndBAmt() { }
    // non-default
    Wine(const char * l, int y, const int yr[], const int bot[]) : label(l), years(y),
        yearAndBAmt(ArrayInt(yr, years), ArrayInt(bot, years)) { }
    Wine(const char * l, int y) : label(l),  years(y),
        yearAndBAmt(ArrayInt(years), ArrayInt(years)) { }
    // destructor
    ~Wine() { }

    // methods
    const std::string & Label() const { return label; }
    int sum() const { return (yearAndBAmt.second()).std::valarray<int>::sum(); }

    // procedures
    void GetBottles();
    void Show() const;
};

#endif // WINE_H_ 


wine.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
30
31
32
33
34
35
#include "wine.h"

using std::cout;
using std::cin;
using std::endl;


// wine methods
void Wine::GetBottles()
{
    int y;
    int b;
    if (years > 0)
    {
        cout << "Enter " << label << " data for " << years << " year(s):\n";
        for (int i = 0; i < years; i++)
        {
            cout << "Enter year: ";
            cin >> y;
            yearAndBAmt.first()[i] = y;
            cout << "Enter bottles for that year: ";
            cin >> b;
            yearAndBAmt.second()[i] = b;
        }
    }
}

void Wine::Show() const
{
    cout << "Wine: " << label << endl;
    cout << "\tYear\tBottles\n";
    for (int i = 0; i < years; i++)
        cout << "\t" << yearAndBAmt.first()[i]
             << "\t" << yearAndBAmt.second()[i] << endl;
}


I wanted to ask about:
1
2
3
4
Wine(const char * l, int y, const int yr[], const int bot[]) : label(l), years(y),
        yearAndBAmt(ArrayInt(yr, years), ArrayInt(bot, years)) { }
Wine(const char * l, int y) : label(l),  years(y),
        yearAndBAmt(ArrayInt(years), ArrayInt(years)) { }


1. What is wrong with const char * parameter?
2. I'm not quite sure what is going on here
yearAndBAmt(ArrayInt(yr, years), ArrayInt(bot, years))
I wanted to call valarrays constructor, but syntax is bit confusing.
Other people used something like:
1
2
3
4
5
6
7
8
9
10
11
Wine::Wine(const char * l, int y, const int yr[], const int bot[])
: arr(y, y)
{
 name = l; // label
 years = y;
 for(int a = 0; a < y; a++)
 {
     arr.first()[a] = yr[a]; // arr is mine yearAndBAmt
     arr.second()[a] = bot[a];
 }
}


or

1
2
3
4
5
6
7
8
9
10
Wine::Wine( const string & l, const int y, const int yr[], const int bot[] )
{
    nazwa = l; // label
    liczba_rocznikow = y; // years
    valarray < int > one( yr, y );
    valarray < int > two( bot, y );
    Pair < valarray < int >, valarray < int > > nowa = Pair < valarray < int >,
valarray < int > >( one, two );
    butelki = nowa;
}


rather than initialization list, but wouldn't that invoke default Pair and valarrays constructors?
Which approach is better?

3. I have feeling that I'm doing something terribly wrong, is in my solution anything like that?
The standard library has std::pair<>, we could directly use it.
http://en.cppreference.com/w/cpp/utility/pair


> The Wine class has ... and a Pair object of valarray<int> objects
> The first member of each Pair object holds the vintage years,
> and the second member holds the numbers of bottles

It would be simpler to use a map where the key is the vintage year and the mapped value is the number of bottles for that year.
http://en.cppreference.com/w/cpp/container/map

> I'm not quite sure what is going on here:
> yearAndBAmt(ArrayInt(yr, years), ArrayInt(bot, years))
> I wanted to call valarrays constructor

ArrayInt( yr, years ) constructs a valarray which copies values from the array yr (number of values is years)
See constructor (4) : http://en.cppreference.com/w/cpp/numeric/valarray/valarray


> rather than initialization list, but wouldn't that invoke default Pair and valarrays constructors?

Yes.

> Which approach is better?

Use the constructor initialiser list as you have done.


> I have feeling that I'm doing something terribly wrong, is in my solution anything like that?

On a cursory glance, your solution appears to be fine.
Topic archived. No new replies allowed.