When to use runtime type information?

If I have different subclasses of something and an algorithm that works with instances of these subclasses, and if the behavior of the algorithm changes slightly depending on which particular subclass is an instance, then the most common object-oriented way is using virtual methods.

For example, if the subclasses are DOM nodes, and if the algorithm should insert a child element of the node, this algorithm differs depending on whether the parent node is a DOM element (which can have children) or a DOM text (which cannot): and therefore the method insertChildren can be virtual (or abstract) in the base class DomNode and is implemented differently in each of the subclasses DomElement and DomText .

Another possibility is to provide instances with a common property whose value can be read: for example, the algorithm can read the nodeType property of the nodeType base class; or for another example, you may have different types (subclasses) of the network packet that have a common packet header, and you can read the packet header to find out what type of packet it has.

I did not use runtime type information, including:

  • is and as keywords in C #
  • downcast
  • Object.GetType method in dot net
  • typeid operator in C ++

When I add a new algorithm that depends on the type of subclass, I instead add a new virtual method to the class hierarchy.

My question is when is it advisable to use information such as runtime instead of virtual functions?

+5
c ++ casting c # oop
Oct 05 '09 at 14:33
source share
5 answers

When there is no other way. Virtual methods are always preferred, but sometimes they simply cannot be used. There are several reasons why this can happen, but the most common is that you do not have the source code of the classes you want to work with, or you cannot change them. This often happens when you are using an outdated system or a commercial closed source library.

In .NET, it can also happen that you need to load new assemblies on the fly, such as plugins, and you usually do not have base classes, but you need to use something like duck input.

+5
Oct 05 '09 at 14:46
source share
โ€” -

In C ++, among some other obscure cases (which mostly deal with lower design options), RTTI is a way to implement so-called multi methods .

+3
Oct 05 '09 at 14:45
source share

These constructs (โ€œisโ€ and โ€œhowโ€) are familiar to Delphi developers, as event handlers usually dump objects into a common ancestor. For example, the OnClick event dispatches a single Sender object: TObject, regardless of the type of object, be it TButton, TListBox, or any other. If you want to know something else about this object, you need to access it through the "how", but to avoid an exception, you can check it with "is" earlier. This downward conversion allows you to associate objects with a constructive type of objects and methods that might not be possible with rigorous class type checking. Imagine that you want to do the same if the user clicks the "Button" or "ListBox" button, but if they provide us with different prototypes of functions, it will not be possible to bind them to the same procedure.

More generally, an object can call a function that notifies that the object, for example, has changed. But he leaves the destination in advance in order to know it โ€œpersonallyโ€ (through as it is), but not necessarily. He does this by passing himself as the most common ancestor of all objects (TObject in case of Delphi)

+1
05 Oct '09 at 15:09
source share

dynamic_cast <>, if I remember correctly, depends on RTTI. Some obscure front ends can also rely on RTTI when an object is passed through a void pointer (for any reason that might happen).

To say it, I have not seen typeof () in the wild for 10 years of work on pro-C ++. (Luckily.)

0
Oct 05 '09 at 14:45
source share

You can refer to More Effective C # for a case where checking the runtime is ok.

Item 3. Specialization of general algorithms Using runtime type checking

You can easily use generics by simply specifying parameters of a new type. A new instance of a new type of parameters means a new type that has similar functionality.

All this is great because you write less code. However, sometimes there are more general tools that do not take advantage of a more specific, but clearly superior, algorithm. C # language rules take this into account. All you need to do is recognize that your algorithm can be more efficient when type parameters have more features, then write this specific code. Moreover, creating a second generic type that defines various constraints does not always work. generic instances are based on the compile time type of the object and not the runtime type. If you do not take this into account, you may be missing out on possible performance.

For example, suppose you are writing a class that provides a reverse-order enumeration for a sequence of elements represented via IEnumerable <T>. To list it back, you can iterate over it and copy the elements to an intermediate collection with indexer access, such as List <T>, and list this collection using a reverse indexer. But if your original IEnumerable is an IList, why not use it and provide a more efficient way (without copying the intermediate collection) to iterate over the elements back. Thus, basically this is a special approach that we can use, but still provide the same behavior (repeating the sequence backwards).

But in general, you should carefully consider checking the type of runtime and make sure that it does not violate the Liskov replacement principle.

0
05 Oct '09 at 14:51
source share



All Articles