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?