C++ and serialization: is there any way to do some kind of introspection?
It isn't used (since it doesn't exist), there's no code examples (since it doesn't exist), and there's no reason to attempt to use it (since it doesn't exist).
The closest you can get is RTTI/dynamic_cast
. But that's not really introspection.
C++ double dispatch extensible without RTTI
The first thing to realize is that double (or higher order) dispatch doesn't scale. With single
dispatch, and n
types, you need n
functions; for double dispatch n^2
, and so on. How you
handle this problem partially determines how you handle double dispatch. One obvious solution is to
limit the number of derived types, by creating a closed hierarchy; in that case, double dispatch can
be implemented easily using a variant of the visitor pattern. If you don't close the hierarchy,
then you have several possible approaches.
If you insist that every pair corresponds to a function, then you basically need a:
std::map<std::pair<std::type_index, std::type_index>, void (*)(Base const& lhs, Base const& rhs)>
dispatchMap;
(Adjust the function signature as necessary.) You also have to implement the n^2
functions, and
insert them into the dispatchMap
. (I'm assuming here that you use free functions; there's no
logical reason to put them in one of the classes rather than the other.) After that, you call:
(*dispatchMap[std::make_pair( std::type_index( typeid( obj1 ) ), std::type_index( typeid( obj2 ) )])( obj1, obj2 );
(You'll obviously want to wrap that into a function; it's not the sort of thing you want scattered
all over the code.)
A minor variant would be to say that only certain combinations are legal. In this case, you can usefind
on the dispatchMap
, and generate an error if you don't find what you're looking for.
(Expect a lot of errors.) The same solution could e used if you can define some sort of default
behavior.
If you want to do it 100% correctly, with some of the functions able to handle an intermediate class
and all of its derivatives, you then need some sort of more dynamic searching, and ordering to
control overload resolution. Consider for example:
Base
/ \
/ \
I1 I2
/ \ / \
/ \ / \
D1a D1b D2a D2b
If you have an f(I1, D2a)
and an f(D1a, I2)
, which one should be chosen. The simplest solution
is just a linear search, selecting the first which can be called (as determined by dynamic_cast
on
pointers to the objects), and manually managing the order of insertion to define the overload
resolution you wish. With n^2
functions, this could become slow fairly quickly, however. Since
there is an ordering, it should be possible to use std::map
, but the ordering function is going to
be decidedly non-trivial to implement (and will still have to use dynamic_cast
all over the
place).
All things considered, my suggestion would be to limit double dispatch to small, closed hierarchies,
and stick to some variant of the visitor pattern.
C++ Downcasting to Derived Class based off Variable
If they've virtual functions, then use dynamic_cast
:
t = dynamic_cast<Triangle*>(shape);
if ( t )
{
//use t
}
But take a note: you should try defining the classes and virtual functions in such a way that you would hardly need to use dynamic_cast
. Prefer well-defined interface, and polymorphism, in general.
Here is one example,
class Shape
{
public:
virtual ~Shape() {} //destructor must be virtual - important!
virtual double Area() const = 0;
};
class Triangle : public Shape
{
public:
Triangle(double a, double b, double c);
virtual double Area() const
{
//calculate area and return it!
}
};
Shape *s = new Triangle(10, 20, 30);
double aread = s->Area(); //calls Triangle::Area()
No need to use shapeType
variable.
Speeding up virtual function calls in gcc
It's sometimes instructive to consider how you'd write the code in good old 'C' if you didn't have C++'s syntactic sugar available. Sometimes the answer isn't using an indirect call. See this answer for an example.
Related Topics
Getting a Boost::Shared_Ptr for This
Why Does Int Main() {} Compile
How to Execute a Piece of Code Only Once
How to Disable Warnings for Particular Include Files
How to Use an Enum Value in a Switch Statement in C++
Linking C++ Code with 'Gcc' (Without G++)
Cpython Is Bytecode Interpreter
How Does the C++ Compiler Know Which Implementation of a Virtual Function to Call
How to Find Longest Common Substring Using C++
C++ Why the Assignment Operator Should Return a Const Ref in Order to Avoid (A=B)=C
How to Get the Type of a Lambda Argument
C++ Integer->Std::String Conversion. Simple Function
C++ Template Function Compiles in Header But Not Implementation
How to Initialize Static Members in the Header
How to Get the Icon, Mime Type, and Application Associated with a File in the Linux Desktop
Cross-Platform Iteration of Unicode String (Counting Graphemes Using Icu)