where downcasting is actually useful?
Asked Answered
T

6

7

I know that downcasting is basically casting parent class pointer or reference to the derived class reference or pointer and for that you use dynamic_cast operator. But i can hardly think of any example. could y'all please explain?

Thirst answered 7/7, 2020 at 14:33 Comment(3)
I've always found the use of a dynamic_cast to be indicative of a design flaw. (Even when I've used it in my own code. Bad Eljay, no biscuit.) There may be valid use cases, but I have not come across those yet.Bibbie
There could be uses of this, usually in complicated frameworks where other design considerations might prevent using a truly virtual interface or provide tangible performance benefits through devirtualization.Nesmith
static_cast can also perform a downcast.Prestige
G
10

The curiously recurring template pattern (CRTP)

where downcasting is actually useful?

It is very useful when implementing the Curiously recurring template pattern:

template <class T> 
struct Base
{
    void interface()
    {
        // ...
        static_cast<T*>(this)->implementation();
        // ...
    }

    static void static_func()
    {
        // ...
        T::static_sub_func();
        // ...
    }
};

struct Derived : Base<Derived>
{
    void implementation();
    static void static_sub_func();
};

The common base class template interface provides definitions that delegates calls to the derived class implementations, realized (for non-static member functions) by downcasting the this pointer of the base class to a pointer type of the respective derived class (for the particular specialization of the base class template) followed by dispatch to a derived class function.

Note that that downcasting in this sense needn't necessarily be implemented in terms of dynamic casting; in this example a static cast is used to cast a base class pointer (this) to the respective derived class pointer.

Gingerly answered 7/7, 2020 at 14:57 Comment(0)
D
2

There are no common idioms / patterns that use dynamic downcasting because it is not very useful. The use of downcasting is indicative of a bad design.

If you find yourself in a rare situation where you think that you need dynamic downcasting because you've been painted into a corner by the design of a framework or a library, then know that dynamic cast is there for you. But most of the time (hopefully), you are not going to be in that situation.

If you cannot think of a case where you would need downcasting, then you are in a good place, and accompanied by most programmers.

For static down casting, see dfri's answer.

Dewan answered 7/7, 2020 at 14:40 Comment(1)
@dfri good point.I was only considering dynamic downcasting in my answer. Static downcasting is indeed useful in CRTP.Dewan
N
2
  1. You obtain abstract class from external/user code you do not trust too much. And you need to verify that it matches the type(s) you expect. If it doesn't match you report error instead of going UB. Furthermore, it would be a problem if you were to expose too much of your code/classes to users/external code - so you hide them behind interface classes.

  2. Useful for general object manager class - which stores abstract class without understanding what are those. So whenever user tries to obtain one of those and cast to appropriate type - it should apply dynamic cast to ensure that user didn't mess up with the types.

  3. It is needed for dealing complex classes with non-trivial hierachies - for which simple pointer cast will probably fail. Though, it is ill adviced to deal with such classes in general.

Negative answered 7/7, 2020 at 14:55 Comment(0)
T
2

The main situations where I've seen downcasting useful in object-oriented frameworks like .NET and Java are those in which all objects implementing a certain interface can be used perform some task a certain way, but some can also be used to perform the task in a faster way. For example, one might have an instance of some type which behaves as a collection that may be read by index, and want to copy a range of items from that type into an array of the item type. If the source object happens to be an instance of a known array-wrapper type that exposes the wrapped array (I think the C++ Vector<T> does that), down-casting to that type, accessing the array, and copying elements from it may be much faster than accessing each individual element through the wrapper.

In most such cases I've seen, the need for downcasting could have been avoided if the base interface had included more methods whose behavior was specified in a way that could be implemented by all types, even if not all implementations would be useful. For example, a "readable by index" collection could include a function that would return a structure containing either an array reference, an offset, and usable range of subscripts (if it wrapped an accessible backing array), or else a null array offset (if the backing array was inaccessible). At least in .NET and I think in Java (not sure about .NET), invoking a method of an interface an object is known to support is faster than testing whether an object supports an interface. I suspect the reason that Java and .NET didn't include such features in many of their widely used interfaces like Enumerable<T> (Java) or IEnumerable<T> (.NET) is that they didn't start out with any support for default interface methods, and thus including such methods would have massively increased the amount of bloat in common implementations.

Tibbitts answered 7/7, 2020 at 15:8 Comment(0)
S
1

Downcasting is widely used in Unreal Engine. There's even a dedicated Cast function that operates on integral representations of UObject-derived types which makes it cheap in terms of performance.

The engine comes with a base hierarchy of types that are supposed to be inherited and extended in your game module. The thing is these types hold base type pointers to themselves, so when you extend these types you will still use the variables defined by base engine types, unless you define your own - which won't give you the full support though.

Code like below is a common sight in Unreal Engine game code bases.

ACharacter* Character = GetCharacter(); // Base engine character type.
AMyCharacter* MyCharacter = Cast<AMyCharacter>(Character); // Extended game character type.

MyCharacter->Something();

This is not to say that it's a manifestation of good architecture but certainly a real life example of the practice.

Struck answered 7/7, 2020 at 15:0 Comment(0)
L
1

Often there are APIs or libraries which use callbacks to notify you of events. Those will usually have a tag that you pass that gets passed back to the callback function.

The problem with such a system is producing unique tags that can be associated back with a code object. The simplest system is to simply cast a pointer to the object to the tag type. That will fail spectacularly if a callback comes in after the object has been destroyed.

I have an alternative, a mixin class that keeps a table of tag numbers and object pointers. The constructor will generate a unique tag ID and place it in a table along with the pointer to the object. The destructor will remove it from the table. But since the pointer stored in the table is the mixin class and not the actual object, you need a cast to make it useful again.

template<typename T>
T* TagMixin::ObjectFromTag(Tag tag)
{
    TagMixin * p = TableLookup(tag);
    if (p == nullptr)  // (not found)
        return nullptr;
    return dynamic_cast<T*>(p);
}
Lebrun answered 7/7, 2020 at 17:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.