Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
B.Eckel - Thinking in C++, Vol.2, 2nd edition.pdf
Скачиваний:
50
Добавлен:
08.05.2013
Размер:
2.09 Mб
Скачать

// before any code that uses pvals is called: pvals.parse(argc, argv, usage); pvals.print();

Animal a;

cout << "Animal a values:" << endl; a.print();

} ///:~

This program can create Animal objects with different characteristics, and those characteristics can be established with the command line. The default characteristics are given in the two-dimensional array of char* called defaults and, after the usage string you can see a global instance of ProgVals called pvals is created; this is important because it allows the rest of the code in the program to access the values.

Note that Animal’s default constructor uses the values in pvals inside its constructor initializer list. When you run the program you can try creating different animal characteristics.

Many command-line programs also use a style of beginning a flag with a hyphen, and sometimes they use single-character flags.

The STL map is used in numerous places throughout the rest of this book.

Multimaps and duplicate keys

A multimap is a map that can contain duplicate keys. At first this may seem like a strange idea, but it can occur surprisingly often. A phone book, for example, can have many entries with the same name.

Suppose you are monitoring wildlife, and you want to keep track of where and when each type of animal is spotted. Thus, you may see many animals of the same kind, all in different locations and at different times. So if the type of animal is the key, you’ll need a multimap. Here’s what it looks like:

//: C04:WildLifeMonitor.cpp #include <vector>

#include <map> #include <string> #include <algorithm> #include <iostream> #include <sstream> #include <ctime> using namespace std;

class DataPoint {

int x, y; // Location coordinates time_t time; // Time of Sighting

Chapter 15: Multiple Inheritance

244

public:

DataPoint() : x(0), y(0), time(0) {} DataPoint(int xx, int yy, time_t tm) :

x(xx), y(yy), time(tm) {}

// Synthesized operator=, copy-constructor OK int getX() { return x; }

int getY() { return y; }

time_t* getTime() { return &time; }

};

string animal[] = {

"chipmunk", "beaver", "marmot", "weasel", "squirrel", "ptarmigan", "bear", "eagle", "hawk", "vole", "deer", "otter", "hummingbird",

};

const int asz = sizeof animal/sizeof *animal; vector<string> animals(animal, animal + asz);

//All the information is contained in a

//"Sighting," which can be sent to an ostream: typedef pair<string, DataPoint> Sighting;

ostream&

operator<<(ostream& os, const Sighting& s) { return os << s.first << " sighted at x= " <<

s.second.getX() << ", y= " << s.second.getY() << ", time = " << ctime(s.second.getTime());

}

// A generator for Sightings: class SightingGen {

vector<string>& animals; static const int d = 100;

public:

SightingGen(vector<string>& an) : animals(an) { srand(time(0)); }

Sighting operator()() { Sighting result;

int select = rand() % animals.size(); result.first = animals[select]; result.second = DataPoint(

rand() % d, rand() % d, time(0)); return result;

Chapter 15: Multiple Inheritance

245

}

};

typedef multimap<string, DataPoint> DataMap; typedef DataMap::iterator DMIter;

int main() {

DataMap sightings; generate_n(

inserter(sightings, sightings.begin()), 50, SightingGen(animals));

//Print everything: copy(sightings.begin(), sightings.end(),

ostream_iterator<Sighting>(cout, ""));

//Print sightings for selected animal: while(true) {

cout << "select an animal or 'q' to quit: "; for(int i = 0; i < animals.size(); i++)

cout <<'['<< i <<']'<< animals[i] << ' '; cout << endl;

string reply; cin >> reply;

if(reply.at(0) == 'q') return 0; istringstream r(reply);

int i;

r >> i; // Converts to int i %= animals.size();

//Iterators in "range" denote begin, one

//past end of matching range: pair<DMIter, DMIter> range =

sightings.equal_range(animals[i]); copy(range.first, range.second,

ostream_iterator<Sighting>(cout, ""));

}

} ///:~

All the data about a sighting is encapsulated into the class DataPoint, which is simple enough that it can rely on the synthesized assignment and copy-constructor. It uses the Standard C library time functions to record the time of the sighting.

In the array of string animal, notice that the char* constructor is automatically used during initialization, which makes initializing an array of string quite convenient. Since it’s easier to use the animal names in a vector, the length of the array is calculated and a vector<string> is initialized using the vector(iterator, iterator) constructor.

Chapter 15: Multiple Inheritance

246

The key-value pairs that make up a Sighting are the string which names the type of animal, and the DataPoint that says where and when it was sighted. The standard pair template combines these two types and is typedefed to produce the Sighting type. Then an ostream operator<< is created for Sighting; this will allow you to iterate through a map or multimap of Sightings and print it out.

SightingGen generates random sightings at random data points to use for testing. It has the usual operator( ) necessary for a function object, but it also has a constructor to capture and store a reference to a vector<string>, which is where the aforementioned animal names are stored.

A DataMap is a multimap of string-DataPoint pairs, which means it stores Sightings. It is filled with 50 Sightings using generate_n( ), and printed out (notice that because there is an operator<< that takes a Sighting, an ostream_iterator can be created). At this point the user is asked to select the animal that they want to see all the sightings for. If you press ‘q’ the program will quit, but if you select an animal number, then the equal_range( ) member function is invoked. This returns an iterator (DMIter) to the beginning of the set of matching pairs, and one indicating past-the-end of the set. Since only one object can be returned from a function, equal_range( ) makes use of pair. Since the range pair has the beginning and ending iterators of the matching set, those iterators can be used in copy( ) to print out all the sightings for a particular type of animal.

Multisets

You’ve seen the set, which only allows one object of each value to be inserted. The multiset is odd by comparison since it allows more than one object of each value to be inserted. This seems to go against the whole idea of “setness,” where you can ask “is ‘it’ in this set?” If there can be more than one of ‘it’, then what does that question mean?

With some thought, you can see that it makes no sense to have more than one object of the same value in a set if those duplicate objects are exactly the same (with the possible exception of counting occurrences of objects, but as seen earlier in this chapter that can be handled in an alternative, more elegant fashion). Thus each duplicate object will have something that makes it unique from the other duplicates – most likely different state information that is not used in the calculation of the value during the comparison. That is, to the comparison operation, the objects look the same but they actually contain some differing internal state.

Like any STL container that must order its elements, the multiset template uses the less template by default to determine element ordering. This uses the contained classes’ operator<, but you may of course substitute your own comparison function.

Consider a simple class that contains one element that is used in the comparison, and another that is not:

//: C04:MultiSet1.cpp

// Demonstration of multiset behavior #include <iostream>

Chapter 15: Multiple Inheritance

247

#include <set> #include <algorithm> #include <ctime> using namespace std;

class X {

char c; // Used in comparison int i; // Not used in comparison

//Don't need default constructor and operator= X();

X& operator=(const X&);

//Usually need a copy-constructor (but the

//synthesized version works here)

public:

X(char cc, int ii) : c(cc), i(ii) {} // Notice no operator== is required

friend bool operator<(const X& x, const X& y) { return x.c < y.c;

}

friend ostream& operator<<(ostream& os, X x) { return os << x.c << ":" << x.i;

}

};

class Xgen { static int i;

// Number of characters to select from: static const int span = 6;

public:

Xgen() { srand(time(0)); } X operator()() {

char c = 'A' + rand() % span; return X(c, i++);

}

};

int Xgen::i = 0;

typedef multiset<X> Xmset;

typedef Xmset::const_iterator Xmit;

int main() { Xmset mset;

Chapter 15: Multiple Inheritance

248

// Fill it with X's: generate_n(inserter(mset, mset.begin()),

25, Xgen());

//Initialize a regular set from mset: set<X> unique(mset.begin(), mset.end()); copy(unique.begin(), unique.end(),

ostream_iterator<X>(cout, " ")); cout << "\n----\n";

//Iterate over the unique values: for(set<X>::iterator i = unique.begin();

i!= unique.end(); i++) {

pair<Xmit, Xmit> p = mset.equal_range(*i); copy(p.first, p.second,

ostream_iterator<X>(cout, " ")); cout << endl;

}

} ///:~

In X, all the comparisons are made with the char c. The comparison is performed with operator<, which is all that is necessary for the multiset, since in this example the default less comparison object is used. The class Xgen is used to randomly generate X objects, but the comparison value is restricted to the span from ‘A’ to ‘E’. In main( ), a multiset<X> is created and filled with 25 X objects using Xgen, guaranteeing that there will be duplicate keys. So that we know what the unique values are, a regular set<X> is created from the multiset (using the iterator, iterator constructor). These values are displayed, then each one is used to produce the equal_range( ) in the multiset (equal_range( ) has the same meaning here as it does with multimap: all the elements with matching keys). Each set of matching keys is then printed.

As a second example, a (possibly) more elegant version of WordCount.cpp can be created using multiset:

//: C04:MultiSetWordCount.cpp //{L} StreamTokenizer

// Count

occurrences of words using a multiset

#include

"StreamTokenizer.h"

#include

"../require.h"

#include

<string>

#include

<set>

#include

<fstream>

#include

<iterator>

using namespace std;

int main(int argc, char* argv[]) { requireArgs(argc, 1);

Chapter 15: Multiple Inheritance

249

Соседние файлы в предмете Численные методы
  • #
    08.05.20133.99 Mб22A.Menezes, P.van Oorschot,S.Vanstone - HANDBOOK OF APPLIED CRYPTOGRAPHY.djvu
  • #
  • #
    08.05.20135.91 Mб24B.Eckel - Thinking in Java, 3rd edition (beta).pdf
  • #
  • #
    08.05.20136.09 Mб17D.MacKay - Information Theory, Inference, and Learning Algorithms.djvu
  • #
    08.05.20133.85 Mб15DIGITAL Visual Fortran ver.5.0 - Programmers Guide to Fortran.djvu
  • #
    08.05.20131.84 Mб12E.A.Lee, P.Varaiya - Structure and Interpretation of Signals and Systems.djvu