What would be a genuinely-acceptable example of usage for a derived cast? I have always thought they are only used when implementing "hacks" but if this is not the case, could someone give an acceptable example of when to use one?
Asked
Active
Viewed 335 times
0
-
1What do you mean by "acceptable"? Acceptable by whom? – Slava Nov 26 '13 at 17:12
-
2I suppose you use it when you have a pointer to `A` and you have no idea (or you have to interrogate the universe to find out) if it's a `B` or a `C`. In this case it would be easier to use dynamic_cast – Raxvan Nov 26 '13 at 17:16
-
1You know, real life is much more complicated than it's described in books. Consider e.g. a situation when you just started a new job and need to deal with legacy code written by your new manager :) which doesn't implement double dispatching so you need to use `dynamic_cast`. And you are so shy so you definitely don't want to start your work by rewriting this code. something like this. – Andriy Tylychko Nov 26 '13 at 17:22
-
The whole point of polymorphism is that the RTTI system can determine the type of the object- which implies no need for dynamic_cast. That is why I am asking is there a legitimate example of its usage? – user997112 Nov 26 '13 at 17:34
1 Answers
1
@user997112
[edit at bottom]
Hello. Below we use a collection of random polymorphic pointers with common ancestor
through the common interface.
Additional work is done with one of the particular derived classes
we need dynamic_cast or typeid to know this ....
main function has the call
then class declarations
then the dynamic cast is at end
delete of objects created with new is not shown
#include <iostream>
#include <algorithm>
#include <random>
#include <exception>
using namespace std;
int dynamic_test();
int main()
{
cout << "Hello world!" << endl;
dynamic_test();
return 0;
}
............
class basex {
public:
virtual ~basex() {};
virtual void work() const = 0;
};
class next1x : public basex {
public:
void work() const override {cout << "1";/*secret*/}
};
class next2x : public basex {
public:
void work() const override {cout << "2";/*secret*/}
};
class next3x : public basex {
public:
void work() const override {cout << "3";/*secret*/}
};
std::vector<basex *> secret_class_picker()
{
//pick classes with common base at random
std::random_device rd;
std::uniform_int_distribution<int> ud(1,3);
std::mt19937 mt(rd());
std::vector<int> random_v;
for (int i = 0; i < 22; ++i)
random_v.push_back( ud(mt) );
cout << "Random" << endl;
for ( auto bq : random_v) //inspecting for human reader
cout << bq << " ";
std::vector<basex *> v;
basex * bptr;
for (auto bq : random_v) {
switch(bq)
{
default: throw std::exception(); break;
case 1: bptr = new next1x; break;
case 2: bptr = new next2x; break;
case 3: bptr = new next3x; break;
}
v.push_back(bptr);
}
cout << "Objects Created " << v.size() << endl;
return v;
}
//this function demands a more derived class
int special_work(const next3x *)
{
//elided
cout <<"[!]";
return 0;
}
int dynamic_test()
{
std::vector<basex *> v = secret_class_picker();//delete these pointer later
cout <<"Working with random polymorphic pointers"<<endl;
for (const auto bq : v)
{
bq->work();//polymorphic
next3x * ptr = dynamic_cast<next3x *>(bq);
if (nullptr != ptr) special_work(ptr); //reserved for particular type
}
return 0;
}
...................... alternative
int dynamic_static_typeid()
{
std::vector<basex *> v = secret_class_picker();
cout <<"Working with random polymorphic pointers"<<endl;
int k(0);
for (const auto bq : v)
{
bool flipflop = (k % 2) == 0;
bq->work();//polymorphic
//cout << "[*]"<< typeid(*bq).name();//dereference
if (flipflop) {
next3x * dc_ptr = dynamic_cast<next3x *>(bq);//not constant time in general
if (nullptr != dc_ptr) {
special_work(dc_ptr); //reserved for particular type
++k;
}
}
else {
if (typeid(next3x) == typeid(*bq)){//constant time
auto sc_ptr = static_cast<next3x *>(bq);//constant time
special_work(sc_ptr);
++k; cout <<"[sc]";
}
}
cout << endl;
}
return 0;
}

VIRTUAL-VOID
- 279
- 1
- 11
-
The normal way to do this would be for `special_work` to be private virtual with an empty base class implementation. – Mark B Nov 26 '13 at 20:18
-
@MarkB Thank You for enhancing the explanation. Different options are always good to state. This is certainly an option if you are allowed to change the interface. Sometimes there are technical and social barriers to this. In my fairy tale constrived example this is just a different option. Stream operator are slightly related to this. We are not talking about namespace std issues but sometimes there are various reason not to change the interface for some special need the is perhaps not of wide spectrum general usage. – VIRTUAL-VOID Nov 26 '13 at 20:40
-
Ok so in this example you're basically saying that you have a vector of many sub types but you only want to call special_work() if you have a sub type of next3x? – user997112 Nov 26 '13 at 22:05
-
I have ammended the example. Perhaps the question has changed to ....efficiency...typeid vs dynamic_cast. Its not easy to get the question you want the first time always. IMHO with little research and no measurements. It is more time efficient to use typeid than dynamic_cast. It is less memory efficient to use typeid than dynamic_cast ... perhaps in some very small sense per type ...not per object. Very real situations exist where a memory is precious on a small memory embedded system ... as opposed to a computer server or data center. I hope some experts add to the discussion. – VIRTUAL-VOID Nov 27 '13 at 19:23