Читаем Thinking In C++. Volume 2: Practical Programming полностью

We can do even better by using a map that associates pointers to type_info objects with a vector of Trash pointers. Since a map requires an ordering predicate, we provide one named TInfoLess that calls type_info::before( ). As we insert Trash pointers into the map, they are associated automatically with their type_info key.

//: C08:Recycle2.cpp

// A Trash Recycler

#include

#include

#include

#include

#include

#include

#include

#include "../purge.h"

using namespace std;

class Trash {

  float wt;

public:

  Trash(float wt) : wt(wt) {}

  virtual float value() const = 0;

  float weight() const { return wt; }

  virtual ~Trash() { cout << "~Trash()\n"; }

};

class Aluminum : public Trash {

  static float val;

public:

  Aluminum(float wt) : Trash(wt) {}

  float value() const { return val; }

  static void value(float newval) {

    val = newval;

  }

};

float Aluminum::val = 1.67;

class Paper : public Trash {

  static float val;

public:

  Paper(float wt) : Trash(wt) {}

  float value() const { return val; }

  static void value(float newval) {

    val = newval;

  }

};

float Paper::val = 0.10;

class Glass : public Trash {

  static float val;

public:

  Glass(float wt) : Trash(wt) {}

  float value() const { return val; }

  static void value(float newval) {

    val = newval;

  }

};

float Glass::val = 0.23;

// Comparator for type_info pointers

struct TInfoLess {

  bool operator()(const type_info* t1, const type_info* t2)

  const {

    return t1->before(*t2);

  }

};

typedef map, TInfoLess>

  TrashMap;

// Sums up the value of the Trash in a bin:

void sumValue(const TrashMap::value_type& p, ostream& os) {

  vector::const_iterator tally = p.second.begin();

  float val = 0;

  while(tally != p.second.end()) {

    val += (*tally)->weight() * (*tally)->value();

    os << "weight of "

       << p.first->name()  // type_info::name()

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

    tally++;

  }

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

}

int main() {

  srand(time(0)); // Seed random number generator

  TrashMap bin;

  // Fill up the Trash bin:

  for(int i = 0; i < 30; i++) {

    Trash* tp;

    switch(rand() % 3) {

      case 0 :

        tp = new Aluminum((rand() % 1000)/10.0);

        break;

      case 1 :

        tp = new Paper((rand() % 1000)/10.0);

        break;

      case 2 :

        tp = new Glass((rand() % 1000)/10.0);

        break;

    }

    bin[&typeid(*tp)].push_back(tp);

  }

  // Print sorted results

  for(TrashMap::iterator p = bin.begin();

      p != bin.end(); ++p) {

    sumValue(*p, cout);

    purge(p->second);

  }

} ///:~

We’ve modified sumValue( ) to call type_info::name( ) directly, since the type_info object is now available there as the first member of the TrashMap::value_type pair. This avoids the extra call to typeid to get the name of the type of Trash being processed that was necessary in the previous version of this program.

<p>Mechanism and overhead of RTTI</p>

Typically, RTTI is implemented by placing an additional pointer in a class’s virtual function table. This pointer points to the type_info structure for that particular type. The effect of a typeid( ) expression is quite simple: the virtual function table pointer fetches the type_info pointer, and a reference to the resulting type_info structure is produced. Since this is just a two-pointer dereference operation, it is a constant time operation.

For a dynamic_cast(source_pointer), most cases are quite straightforward: source_pointer’s RTTI information is retrieved, and RTTI information for the type destination* is fetched. A library routine then determines whether source_pointer’s type is of type destination* or a base class of destination*. The pointer it returns may be adjusted because of multiple inheritance if the base type isn’t the first base of the derived class. The situation is (of course) more complicated with multiple inheritance in which a base type may appear more than once in an inheritance hierarchy and virtual base classes are used.

Because the library routine used for dynamic_cast must check through a list of base classes, the overhead for dynamic_cast may be higher than typeid( ) (but of course you get different information, which may be essential to your solution), and it may take more time to discover a base class than a derived class. In addition, dynamic_cast allows you to compare any type to any other type; you aren’t restricted to comparing types within the same hierarchy. This adds extra overhead to the library routine used by dynamic_cast.

<p>Summary</p>
Перейти на страницу:

Похожие книги

3ds Max 2008
3ds Max 2008

Одни уверены, что нет лучшего способа обучения 3ds Мах, чем прочитать хорошую книгу. Другие склоняются к тому, что эффективнее учиться у преподавателя, который показывает, что и как нужно делать. Данное издание объединяет оба подхода. Его цель – сделать освоение 3ds Мах 2008 максимально быстрым и результативным. Часто после изучения книги у читателя возникают вопросы, почему не получился тот или иной пример. Видеокурс – это гарантия, что такие вопросы не возникнут: ведь автор не только рассказывает, но и показывает, как нужно работать в 3ds Мах.В отличие от большинства интерактивных курсов, где работа в 3ds Мах иллюстрируется на кубиках-шариках, данный видеокурс полностью практический. Все приемы работы с инструментами 3ds Мах 2008 показаны на конкретных примерах, благодаря чему после просмотра курса читатель сможет самостоятельно выполнять даже сложные проекты.

Владимир Антонович Верстак , Владимир Верстак

Программирование, программы, базы данных / Программное обеспечение / Книги по IT