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

This example is much shorter, since most of the code in the original example was just the overhead for checking the casts. The target type of a dynamic_cast is placed in angle brackets, like the other new-style C++ casts (static_cast, and so on), and the object to cast appears as the operand. dynamic_cast requires that the types you use it with be polymorphic if you want safe downcasts.[105] This in turn requires that the class must have at least one virtual function. Fortunately, the Security base class has a virtual destructor, so we didn’t have to invent some extraneous function to get the job done. dynamic_cast does its work at runtime, of course, since it has to check the virtual function table of objects according to there dynamic type. This naturally implies that dynamic_cast tends to be more expensive than the other new-style casts.

You can also use dynamic_cast with references instead of pointers, but since there is no such thing as a null reference, you need another way to know if the cast fails. That "other way" is to catch a bad_cast exception, as follows:

  Metal m;

  Security& s = m;

  try {

    Investment& c = dynamic_cast(s);

    cout << "  it's an Investment\n";

  }

  catch (bad_cast&) {

    cout << "s is not an Investment type\n";

  }

The bad_cast class is defined in the header, and, like most of the standard library, is declared in the std namespace.

<p>The typeid operator</p>

The other way to get runtime information for an object is through the typeid operator. This operator returns an object of class type_info, which yields information about the type of object to which it was applied. If the type is polymorphic, it gives information about the most derived type that applies (the dynamic type); otherwise it yields static type information. One use of the typeid operator is to get the name of the dynamic type of an object as a const char*, as you can see in the following example.

//: C08:TypeInfo.cpp

// Illustrates the typeid operator

#include

#include

using namespace std;

struct PolyBase {virtual ~PolyBase(){}};

struct PolyDer : PolyBase {};

struct NonPolyBase {};

struct NonPolyDer : NonPolyBase {NonPolyDer(int){}};

int main() {

  // Test polymorphic Types

  const PolyDer pd;

  const PolyBase* ppb = &pd

  cout << typeid(ppb).name() << endl;

  cout << typeid(*ppb).name() << endl;

  cout << boolalpha << (typeid(*ppb) == typeid(pd))

    << endl;

  cout << (typeid(PolyDer) == typeid(const PolyDer))

    << endl;

  // Test non-polymorphic Types

  const NonPolyDer npd(1);

  const NonPolyBase* nppb = &npd

  cout << typeid(nppb).name() << endl;

  cout << typeid(*nppb).name() << endl;

  cout << (typeid(*nppb) == typeid(npd))

    << endl;

  // Test a built-in type

  int i;

  cout << typeid(i).name() << endl;

} ///:~

The output from this program is

struct PolyBase const *

struct PolyDer

true

true

struct NonPolyBase const *

struct NonPolyBase

false

int

The first output line just echoes the static type of ppb because it is a pointer. To get RTTI to kick in, you need to look at the object a pointer or reference is connected to, which is illustrated in the second line. Notice that RTTI ignores top-level const and volatile qualifiers. With non-polymorphic types, you just get the static type (the type of the pointer itself). As you can see, built-in types are also supported.

It turns out that you can’t store the result of a typeid operation in a type_info object, because there are no accessible constructors and assignment is disallowed; you must use it as we have shown. In addition, the actual string returned by type_info::name( ) is compiler dependent. Some compilers return "class C" instead of just "C", for instance, for a class named C. Applying typeid to an expression that dereferences a null pointer will cause a bad_typeid exception (also defined in ) to be thrown.

The following example shows that the class name that type_info::name( ) returns is fully qualified.

//: C08:RTTIandNesting.cpp

#include

#include

using namespace std;

class One {

  class Nested {};

  Nested* n;

public:

  One() : n(new Nested) {}

  ~One() { delete n; }

  Nested* nested() { return n; }

};

int main() {

  One o;

  cout << typeid(*o.nested()).name() << endl;

} ///:~

Since Nested is a member type of the One class, the result is One::Nested.

You can also ask a type_info object if it precedes another type_info object in the implementation-defined "collation sequence" (the native ordering rules for text), using before(type_info&), which returns true or false. When you say,.

if(typeid(me).before(typeid(you))) // ...

you’re asking if me occurs before you in the current collation sequence. This is useful should you use type_info objects as keys.

<p>Casting to intermediate levels</p>
Перейти на страницу:

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

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

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