Re: Replacing a void* in C++
* Jim Langston:
"Alf P. Steinbach" <alfps@start.no> wrote in message
news:13fqklnhr18ik5b@corp.supernews.com...
* Jim Langston:
Trying to google for "change void* in C++" doesn't help has void is found
too many places in function/method returns. It looks like somewhere I'm
going to have to do a dymaic_cast or a reinterpret_cast and am trying to
stick any such ugliness away from the onmessage methods.
Check out the visitor pattern.
I've been reading up on the visitor pattern, and if I was to develop this
class heirarchy from scratch, I'd probalby use that. However, I don't see
how using the visitor pattern helps with converting a void * in an existing
class heirarchy. Unless I'm missing something or my googles for "visitor
pattern c++" are not showing a specific usage for this case.
OK.
Let's first dispense with the strings in your code, because /that's not
guaranteed to work/. Or more precisely, I'd have to scrutinize the
standard to find a statement guaranteeing uniqueness of
typeid(T).name(), and I don't think there is such a statement. So,
first take, in the Process Of Transforming Jim's Code:
<code>
#include <iostream>
#include <ostream>
#include <typeinfo>
#include <string>
struct AIMsg
{
public:
AIMsg() {}
virtual std::type_info const& valueType() const = 0;
virtual ~AIMsg() {}
};
template <class T> class Message: public AIMsg
{
public:
Message() {}
virtual std::type_info const& valueType() const
{
return typeid( T );
}
T value;
};
void messageHandler( AIMsg const& msg )
{
if ( msg.valueType() == typeid(float) )
{
std::cout
<< dynamic_cast<Message<float> const*>( &msg )->value
<< "\n";
}
if ( msg.valueType() == typeid(int) )
{
std::cout
<< dynamic_cast<Message<int> const*>( &msg )->value
<< "\n";
}
}
int main()
{
Message<float> Bar;
Bar.value = 54321.123f;
messageHandler( Bar );
Message<int> Bar2;
Bar2.value = 123;
messageHandler( Bar2 );
}
</code>
Next, we recall that in C++, explicit discrimination on type is usually
best replaced with use of a virtual function. In the derived class
where the implementation of that virtual function is executed, the exact
derived type is known. So then it can call a templated handler, take 2:
<code>
#include <iostream>
#include <ostream>
#include <typeinfo>
#include <string>
struct AIMsg
{
public:
AIMsg() {}
virtual std::type_info const& valueType() const = 0;
virtual void callHandler() const = 0;
virtual ~AIMsg() {}
};
template <class T> class Message;
template< typename T > void handle( Message<T> const& );
template <class T> class Message: public AIMsg
{
public:
Message() {}
virtual std::type_info const& valueType() const
{
return typeid( T );
}
virtual void callHandler() const
{
handle( *this );
}
T value;
};
template< typename T >
void handle( Message<T> const& msg )
{
std::cout << msg.value << "\n";
}
int main()
{
Message<float> Bar;
Bar.value = 54321.123f;
Bar.callHandler();
Message<int> Bar2;
Bar2.value = 123;
Bar2.callHandler();
}
</code>
I don't know whether you need the type-info name for something (like
e.g. tracing or logging) so I left it in, but note that at least in the
code above it's no longer used, and could just be removed.
To make this a full-fledged visitor pattern you'd have to pass an object
to callHandler(), and let that object provide a templatized handle()
member function. But that's just needless complication for the task
above. You can regard the above as a special case visitor pattern.
Cheers, & hth.,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?