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

(*it)->accept(sval);

cout << string(sval) << endl;

}

// Perform "Bee" operation on all Flowers: Bee bee;

for(it = v.begin(); it != v.end(); it++) (*it)->accept(bee);

purge(v); } ///:~

Efficiency

Flyweight

The composite

Evolving a design: the trash recycler

The nature of this problem (modeling a trash recycling system) is that the trash is thrown unclassified into a single bin, so the specific type information is lost. But later, the specific type information must be recovered to properly sort the trash. In the initial solution, RTTI (described in Chapter XX) is used.

This is not a trivial design because it has an added constraint. That’s what makes it interesting

– it’s more like the messy problems you’re likely to encounter in your work. The extra constraint is that the trash arrives at the trash recycling plant all mixed together. The program must model the sorting of that trash. This is where RTTI comes in: you have a bunch of anonymous pieces of trash, and the program figures out exactly what type they are.

One of the objectives of this program is to sum up the weight and value of the different types of trash. The trash will be kept in (potentially different types of) containers, so it makes sense to templatize the “summation” function on the container holding it (assuming that container exhibits basic STL-like behavior), so the function will be maximally flexible:

//: C09:sumValue.h

//Sums the value of Trash in any type of STL

//container of any specific type of Trash:

Chapter 16: Design Patterns

466

#ifndef SUMVALUE_H #define SUMVALUE_H #include <typeinfo> #include <vector>

template<typename Cont>

void sumValue(const Cont& bin) { double val = 0.0f;

typename Cont::iterator tally = bin.begin(); while(tally != bin.end()) {

val +=(*tally)->weight() * (*tally)->value(); out << "weight of "

<<typeid(*(*tally)).name()

<<" = " << (*tally)->weight()

<<endl;

tally++;

}

out << "Total value = " << val << endl;

}

#endif // SUMVALUE_H ///:~

When you look at a piece of code like this, it can be initially disturbing because you might wonder “how can the compiler know that the member functions I’m calling here are valid?” But of course, all the template says is “generate this code on demand,” and so only when you call the function will type checking come into play. This enforces that *tally produces an object that has member functions weight( ) and value( ), and that out is a global ostream.

The sumValue( ) function is templatized on the type of container that’s holding the Trash pointers. Notice there’s nothing in the template signature that says “this container must behave like an STL container and must hold Trash*”; that is all implied in the code that’s generated which uses the container.

The first version of the example takes the straightforward approach: creating a vector<Trash*>, filling it with Trash objects, then using RTTI to sort them out:

//: C09:Recycle1.cpp // Recycling with RTTI #include "sumValue.h" #include "../purge.h" #include <fstream> #include <vector> #include <typeinfo> #include <cstdlib> #include <ctime>

using namespace std;

ofstream out("Recycle1.out");

Chapter 16: Design Patterns

467

class Trash { double _weight;

static int _count; // # created static int _dcount; // # destroyed

//disallow automatic creation of

//assignment & copy-constructor: void operator=(const Trash&); Trash(const Trash&);

public:

Trash(double wt) : _weight(wt) { _count++;

}

virtual double value() const = 0;

double weight() const { return _weight; } static int count() { return _count; } static int dcount() { return _dcount;} virtual ~Trash() { _dcount++; }

};

int Trash::_count = 0; int Trash::_dcount = 0;

class Aluminum : public Trash { static double val;

public:

Aluminum(double wt) : Trash(wt) {} double value() const { return val; } static void value(double newval) {

val = newval;

}

~Aluminum() { out << "~Aluminum\n"; }

};

double Aluminum::val = 1.67F;

class Paper : public Trash { static double val;

public:

Paper(double wt) : Trash(wt) {} double value() const { return val; } static void value(double newval) {

val = newval;

}

~Paper() { out << "~Paper\n"; }

Chapter 16: Design Patterns

468

};

double Paper::val = 0.10F;

class Glass : public Trash { static double val;

public:

Glass(double wt) : Trash(wt) {} double value() const { return val; } static void value(double newval) {

val = newval;

}

~Glass() { out << "~Glass\n"; }

};

double Glass::val = 0.23F;

class TrashGen { public:

TrashGen() { srand(time(0)); } static double frand(int mod) {

return static_cast<double>(rand() % mod);

}

Trash* operator()() {

for(int i = 0; i < 30; i++) switch(rand() % 3) {

case 0 :

return new Aluminum(frand(100)); case 1 :

return new Paper(frand(100)); case 2 :

return new Glass(frand(100));

}

return new Aluminum(0); // Or throw exeception...

}

};

int main() { vector<Trash*> bin;

// Fill up the Trash bin: generate_n(back_inserter(bin), 30, TrashGen()); vector<Aluminum*> alBin;

vector<Paper*> paperBin;

Chapter 16: Design Patterns

469

vector<Glass*> glassBin; vector<Trash*>::iterator sorter = bin.begin(); // Sort the Trash:

while(sorter != bin.end()) { Aluminum* ap =

dynamic_cast<Aluminum*>(*sorter);

Paper* pp = dynamic_cast<Paper*>(*sorter); Glass* gp = dynamic_cast<Glass*>(*sorter); if(ap) alBin.push_back(ap);

if(pp) paperBin.push_back(pp); if(gp) glassBin.push_back(gp); sorter++;

}

sumValue(alBin);

sumValue(paperBin);

sumValue(glassBin);

sumValue(bin);

out << "total created = "

<<Trash::count() << endl; purge(bin);

out << "total destroyed = "

<<Trash::dcount() << endl;

}///:~

This uses the classic structure of virtual functions in the base class that are redefined in the derived class. In addition, there are two static data members in the base class: _count to indicate the number of Trash objects that are created, and _dcount to keep track of the number that are destroyed. This verifies that proper memory management occurs. To support this, the operator= and copy-constructor are disallowed by declaring them private (no definitions are necessary; this simply prevents the compiler from synthesizing them). Those operations would cause problems with the count, and if they were allowed you’d have to define them properly.

The Trash objects are created, for the sake of this example, by the generator TrashGen, which uses the random number generator to choose the type of Trash, and also to provide it with a “weight” argument. The return value of the generator’s operator( ) is upcast to Trash*, so all the specific type information is lost. In main( ), a vector<Trash*> called bin is created and then filled using the STL algorithm generate_n( ). To perform the sorting, three vectors are created, each of which holds a different type of Trash*. An iterator moves through bin and RTTI is used to determine which specific type of Trash the iterator is currently selecting, placing each into the appropriate typed bin. Finally, sumValue( ) is applied to each of the containers, and the Trash objects are cleaned up using purge( ) (defined in Chapter XX). The creation and destruction counts ensure that things are properly cleaned up.

Of course, it seems silly to upcast the types of Trash into a container holding base type pointers, and then to turn around and downcast. Why not just put the trash into the appropriate

Chapter 16: Design Patterns

470

Соседние файлы в предмете Численные методы
  • #
    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