A lot of the codebase I work on is deployed as COM servers. This means that it isn’t uncommon to pass an array of objects as an of pointers to base (i.e. IUnknown) and then downcast to the specific interface you want using QueryInterface.
I found myself in a similar situation with some more modern C++, where I had a std::vector<std::shared_ptr> and wanted to convert each pointer to a shared_ptr in order to call into some API method. The question is – if you have a std::shared_ptr<T1>, how to cast it to a std::shared_ptr<T2> (for suitably related T1 and T2)?
This question was already asked on StackOverflow and the answers pointed me at std::dynamic_pointer_cast and std::static_pointer_cast, which are analogous to static_cast/dynamic_cast for raw pointers.
class B { public: virtual void Print(){ std::cout << "Object type B\n"; } virtual ~B(){}; }; class C : public B { public: virtual void Print(){ std::cout << "Object type C\n"; } void BehaveLikeC() {std::cout << "Behave like C\n";} }; class D : public B { public: virtual void Print(){ std::cout << "Object type D\n"; } void BehaveLikeD() { std::cout << "Behave like D\n"; } }; void DoSomething( const std::shared_ptr<D>& d ) { d->BehaveLikeD(); } int _tmain(int argc, _TCHAR* argv[]) { std::vector<std::shared_ptr<b>> elements; elements.push_back( std::make_shared<C>() ); elements.push_back( std::make_shared<D>() ); // Call base class method on all elements std::for_each( elements.begin(), elements.end(), []( const std::shared_ptr<b>& b ){ b->Print(); }); // Call C behaviour on all C elements for ( size_t i = 0; i < elements.size(); ++i ) { auto c = std::dynamic_pointer_cast( elements[i] ); if (c ){ c->BehaveLikeC(); } auto d = std::dynamic_pointer_cast<D>( elements[i] ); if (d){ DoSomething(d); } } return 0; }
Just as a matter of style, I prefer to write the if-cast-then logic something like this:
for( auto& element : elements )
{
if( auto c = std::dynamic_pointer_cast( element ) )
{
c->BehaveLikeC();
}
if( auto d = std::dynamic_pointer_cast( element ) )
{
DoSomething(d);
}
}
}
So, ‘c’ and ‘d’ are only accessible in scopes where they’re non-null (that way, you can’t trip over them further down the function)
(P.S. It looks like WordPress has eaten some of your code again… – and no doubt has done the same to mine… – if so, you can see it at https://gist.github.com/PureAbstract/5852655)
Cheers,
Andy