class Base {
virtual void func1();
}
class Derived : Base {
void func1();
void func2();
}
vector<Base *> vec;
vec.push_back(new Base()), vec.push_back(new Derived());
What is the correct/clean way to call func2 without knowing which index corresponds to which class? Is there a convention to do such a thing? I also want to avoid using typeid.
In your case the objects are sliced, as mentioned in king_nak's answer, so there's no safe way to call func2().
But you can store pointers to Base instead of Base objects - in this case you can use dynamic_cast:
std::vector<Base*> vec;
vec.push_back(new Base());
vec.push_back(new Derived());
for (auto obj : vec)
{
Derived* d = dynamic_cast<Derived*>(obj);
if (d)
{
d->func2();
}
}
Some info on dynamic_cast: link
PS: Also, if you want to call function func2() on Base objects, I think it makes sense to add a stupid implementation to Base class and make the function virtual.
This function will take one of said pointers and call func2 if possible, and simply return false otherwise
bool CallFunc2(Base* Bae){
Derived* Der;
if (Der = dynamic_cast<Derived*>(Bae))
{Der->func2(); return true;}
else
return false;
}
This works on the principle that dynamic_cast returns a null pointer if the object being cast cannot be converted.
If you don't want to use RTTI at all (including dynamic_cast), you could simulate its behaviour like Qt does it with qgraphicsitem_cast
Outline:
class Base {
public:
enum { Type = 0 };
virtual int type() { return Type; }
};
class Derived : public Base {
public:
enum { Type = 1 };
int type() { return Type; }
};
template<typename T>
inline T myobject_cast(Base *b) {
if (b) {
// Requires C++11
if (int(std::remove_pointer<T>::type::Type) == b->type()) {
return static_cast<T>(b);
}
/* Pre C++11 (might be UB, but works on many compilers, OpenSource and Commercial)
if (int(static_cast<T>(0)->Type) == b->type()) {
return static_cast<T>(b);
}
*/
}
return NULL;
}
// use:
Base *b = new Base;
Base *d = new Derived;
Derived *o1 = myobject_cast<Derived*> (b); // NULL
Derived *o2 = myobject_cast<Derived*> (d); // d
Each class would require a unique Type member for this to work.
Be aware that this will not work with "intermediate" classes in the hierarchy. Only the actual, most derived type will can be cast to (e.g. a DerivedDerived cannot be cast to a Derived, or Base for that matter).
You might also find an overload for const handy:
template<typename T> inline T myobject_cast(const Base *b)
{ return (b && int(static_cast<T>(0)->Type) == b->type()) ? static_cast<T>(p) : 0; }
const Base *cb = new Derived;
const Derived *co = myobject_cast<const Derived *>(cb);
Related
In our legacy project we have a function that takes reference to a base class and creates a copy of the derived class on the heap. This is solved essentially like this: https://godbolt.org/z/9ooM4x
#include <iostream>
class Base
{
public:
virtual Base* vclone() const = 0;
int a{7};
};
class Derived : public Base
{
public:
Derived()
{
a = 8;
}
Base* vclone() const override
{
return new Derived(*this);
}
};
Base* clone(const Base& original)
{
return original.vclone();
}
int main()
{
Derived d1;;
auto* d2 = clone(d1);
std::cout << d2->a << std::endl;
}
This works, but I would like to get rid of the boilerplate vclone method that we have to have in every single derived class.
We have hundreds of derived classes, some of them derived not directly from Base, but from some of the other derived classes too. So if we forget to override the vclone method, we may not even get a warning of the slicing that will happen.
Now, there is much to say about such a design, but this is 10-15 year old code that I try to modernize step by step. What I do look for, is a templatized version of clone that does not depend on a virtual method. What I want, is a clone function like this:
Base* clone(const Base& original)
{
return new <Actual Derived Type>(original);
}
The actual derived type is somewhat known, since a dynamic_cast will fail if trying to cast to it with wrong type, but I don't know if it is possible to access the actual type in a way that I want.
Any help would be appreciated.
I also think you probably cannot improve the code in the sense to make it shorter.
I would say this implementation is basically the way to go.
What you could do is to change the return value of Derived::clone to Derived *. Yes C++ allows this.
Then a direct use of Derived::clone yields the correct pointer type and Base::clone still works as expected
class Derived : public Base
{
public:
Derived()
{
a = 8;
}
Derived* vclone() const override // <<--- 'Derived' instead of 'Base'.
{
return new Derived(*this);
}
};
I would also rename to vclone member function to clone (There is no need to have two names).
The free function clone could be made a template so that it works for all classes and returns the right pointer type
template <class T>
T *clone(const T *cls)
{
return cls->clone();
}
However, all these changes do not make the code shorter, just more usable and perhaps more readable.
To make it a little shorter you might use an CRTP approach.
template <class Derived, class Base>
class CloneHelper: public Base {
Derived* vclone() const override
{
return new Derived(* static_cast<Derived *>(this) );
}
};
// then use
class Derived : public CloneHelper<Derived, Base>
{
public:
Derived()
{
a = 8;
}
};
However, I am not sure if it is worth it. One still must not forget the CloneHelper, it makes inheritance always public and you cannot delegate to the Base constructor so easily and it is less explicit.
You could use an outside clone function and typeid:
#include <typeindex>
#include <string>
#include <stdexcept>
#include <cassert>
template<class Derived_t, class Base_t>
Base_t *clone_helper(Base_t *b) {
return new Derived_t(*static_cast<Derived_t *>(b));
}
struct Base {
virtual ~Base() = default;
};
struct Derived : Base {};
Base *clone(Base *b) {
const auto &type = typeid(*b);
if (type == typeid(Base)) {
return clone_helper<Base>(b);
}
if (type == typeid(Derived)) {
return clone_helper<Derived>(b);
}
throw std::domain_error(std::string("No cloning provided for type ") + typeid(*b).name());
}
int main() {
Derived d;
Base *ptr = &d;
auto ptr2 = clone(ptr);
assert(typeid(*ptr2) == typeid(Derived));
}
This will find at runtime if you did not provide a clone method. It may be slower than usual. Sadly a switch is not possible since we cannot obtain the typeid of a type at compile time.
You may like to implement clone function in a separate class template, which is only applied to derived classes when an object of a derived class is created. The derived classes do not implement clone (keep it pure virtual) to avoid forgetting to override it in a further derived class.
Example:
struct Base {
virtual Base* clone() const = 0;
virtual ~Base() noexcept = default;
};
template<class Derived>
struct CloneImpl final : Derived {
using Derived::Derived;
CloneImpl* clone() const override { // Covariant return type.
return new CloneImpl(*this);
}
};
template<class T>
std::unique_ptr<T> clone(T const& t) { // unique_ptr to avoid leaks.
return std::unique_ptr<T>(t.clone());
}
struct Derived : Base {};
struct Derived2 : Derived {};
int main() {
CloneImpl<Derived> d1; // Apply CloneImpl to Derived when creating an object.
auto d2 = clone(d1);
auto d3 = clone(*d2);
CloneImpl<Derived2> c1; // Apply CloneImpl to Derived2 when creating an object.
auto c2 = clone(c1);
auto c3 = clone(*c2);
}
See https://stackoverflow.com/a/16648036/412080 for more details about implementing interface hierarchies without code duplication.
I have a function that looks like:
// this function might modify base_ptr
void SomeFunction(shared_ptr<Base> &base_ptr)
{ if(some_condition) { base_ptr = some_other_ptr; } }
I'd like to call the function with a shared_ptr:
shared_ptr<Derived> d = ...;
SomeFunction(d);
This doesn't work though. It doesn't work if I'm using normal pointers either (ie. implicit casting to Base* & from Derived*. One workaround is to create a Base pointer from the Derived one, and then pass that to the function.
shared_ptr<Base> base = d;
SomeFunction(b);
But this isn't very pretty from a coding standpoint. It also adds confusion and the potential for a subtle bug:
shared_ptr<Derived> d = derived;
shared_ptr<Base> b = derived;
SomeFunction(b);
// b and d might now be pointing to different things -- not good!
Is there better way to do this?
What you are trying to do is inherently dangerous, and C++ is making it hard on purpose. Consider if C++ allowed you to call SomeFunction the way you wanted. Then you could do this:
struct Base {
};
struct Derived1 : Base {
void f1();
};
struct Derived2 : Base {
void f2();
};
void SomeFunction(shared_ptr<Base> &p)
{
p = make_shared<Derived2>(); // nothing wrong with converting
// a Derived2 pointer to a Base pointer.
}
int main()
{
shared_ptr<Derived1> d = make_shared<Derived1>();
SomeFunction(d); // An error, but what if it wasn't?
d->f1(); // Trying to call method f1 of a Derived2!
}
The compiler would not be able to know that d changed from a Derived1 pointer to a Derived2 pointer, so it wouldn't be able to give you a compile error when you tried to call method f1 of a Derived2.
You could template the function for the smart pointer's type
#include <iostream>
#include <memory>
#include <type_traits>
using namespace std;
class Base {
public:
virtual void hello() {
cout << "hello base" << endl;
}
};
class Derived : public Base {
public:
void hello() {
cout << "hello derived" << endl;
}
};
class otherClass {
public:
};
template<typename T>
void SomeFunction(shared_ptr<T> &base_ptr)
{
static_assert(is_base_of<Base, T>::value == true, "Wrong non-derived type");
base_ptr->hello();
// Rebase it
base_ptr.reset(new Derived);
base_ptr->hello();
}
int main() {
shared_ptr<Base> obj(new Base());
SomeFunction(obj);
// hello base
// hello derived
shared_ptr<Derived> obj2(new Derived());
// hello derived
// hello derived
SomeFunction(obj2);
shared_ptr<otherClass> obj3(new otherClass());
SomeFunction(obj3); // ASSERT
return 0;
}
http://ideone.com/ATqhEZ
If you intend to update all the smart pointers when you reset one, you'll have to do some book-keeping by yourself since they're not designed to have a "signal-like" mechanism to notify other smart pointers pointing to the same object.
Edited my answer to provide compile-time safety if you intend to use it with Base and relative subclasses.
Warning: the above solution uses C++11, the same could be accomplished in a similar way in pre-C++11 code
I know there are solved questions related to this issue, but I still can't figure out how to resolve my problem.
I have something like this:
class Base
{
static Base* createBase()
{
Base *b = new Base();
... //does a lot of weird things
return b;
}
}
class Child : public Base
{
static Child* createChild()
{
Child *c = createBase(); // error
return c;
}
}
I know why it doesn't work, but I have to find a way to do it. The createBase function does a lot of things so I don't want to recode it.
Any suggestions?
Why do you expect that to work? You can't treat a Base object as if it were a Child object, because the Child class might have all sorts of additional data that Base does not.
In order to get the effect you're looking for, there are two ways to do it:
The first way, and probably the best idea, is to move the logic from createBase into the Base constructor. The Base constructor will run whether you're creating a Base or something derived from it. It looks like you're trying to do the work of initializing the base object, and that's exactly what constructors are for!
If for some reason this will not work in your case, the other option is to create a protected initialize method in Base which accepts a Base* and does all the work that you are currently doing in createBase, e.g.
class Base
{
public:
static Base* createBase()
{
Base* b = new Base();
initialize(b);
return b;
}
protected:
static void initialize(Base* b)
{
... //does a lot of weird things
}
}
class Child : public Base
{
public:
static Child* createChild()
{
Child *c = new Child();
initialize(c):
return c;
}
}
Note that this works since, while you can't treat a Base* as if it were a Child*, you can go the other way and treat a Child* as if it were a Base*, because the Child class is guaranteed to have at least everything that the Base class does, due to the nature of inheritance.
Edit: I saw you post in a comment to another answer that you cannot modify the definition of Base. In that case, you are completely out of luck and you will have to accept the need to copy-and-paste, given the restrictions in play. You are not going to be able to call createBase and get back a pointer to an object of any type other than Base if you cannot modify its code.
overloading new for Base class might solve your issue.
class UTIL{
static size_t size;
public:
static void setSize(size_t t)
{
//mutex protection
size = t;
}
static size_t getsize(); // should only be called from inside new of class A
};
class A
{
int i;
public:
static A* createA()
{
A* a = new A();
a->i = 10;
return a;
}
void* operator new (size_t size) throw (const char *){
void * p = malloc(UTIL::getsize());
if (p == 0) throw "allocation failure";
return p;
}
void operator delete (void *p){
free(p);
}
};
size_t UTIL::size = sizeof(A);
size_t UTIL::getsize()
{
//mutex protection
size_t tmp = size;
size = sizeof(A);
return tmp;
}
class B
{
public:
int j;
static B* createB()
{
//take mutex
UTIL::setSize(sizeof(B));
B* b = (B*)(A::createA());
b->j = 20;
//release Mutex
return b;
}
};
Perhaps you should re-define createBase as follows:
template< class TheClass > static TheClass* create()
{
TheClass *ret = new TheClass();
... //does a lot of weird things
return ret;
}
You can then create an object as follows:
Child* pChild = create< Child >();
This may not be appropriate depending what the "weird" things are but its one possible way of solving your issues.
You should be using
Child *c = new Child();
Otherwise you are trying to create a Base class instance and call it a Child.
RE your comment:
Perhaps you could change
static Base* createBase();
static void createBase(Base *b);
If you pass the instance into this method you could use it with both Child and Base
for example:
Base *b = new Base();
Base::createBase(b);
Child *c = new Child();
Base::createBase(c);
or alternatively
static Base *createBase(Base *b = NULL){
if(b == NULL){
b = new Base;
}
//do your stuff
return b;
and for the child:
static Child* createChild(){
Child *c = new Child;
createBase(c);
return c;
This way you can use both:
b = Base::createBase();
c = Child::createChild();
Don't the "weird" things belong in the Base constructor. Then by constructing the Child your base gets properly constructed?
Otherwise just refactor the code into a method you call from both places - definately don't copy it.
You can use constructors to do the work for you:
class Base
{
Base()
{
// does a lot of weird things
}
static Base* createBase()
{
return new Base();
}
};
class Child : public Base
{
Child()
{
// Do child's weird things here
}
static Child* createChild()
{
return new Child();
}
};
Base *instance1 = new Child(); // Works as expected
Base *instance2 = Child::createChild(); // Works as expected
Base *instance3 = new Base(); // Works as expected
Base *instance4 = Base::createBase(); // Works as expected
EDIT:
If you can't modify the Base class, you shouldn't derive from it this way. The class is apparently meant to have its own functionality and the static construction method suggests some more complex usage. You might want to use the Decorator design pattern instead of inheritance in this case: http://en.wikipedia.org/wiki/Decorator_pattern
how about this
class Base
{
public:
static Base* createBase()
{
Base *b = new Base();
//does a lot of weird things
return b;
}
};
class Child
{
protected:
Base* m_basePtr;
public:
operator Base&(){return *m_basePtr;}
static Child* createChild()
{
Child *c=new Child;
c->m_basePtr=Base::createBase();
return c;
}
};
but you have to delete the pointer at the destructor
What you want to do is:
class Base
{
Base()
{
... //does a lot of weird things
}
};
class Child : public Base
{
Child Child() // This calls the base constructor auto-magically
{
}
}
int main()
{
Child childOne;
Base baseOne;
Child* childPtr = new Child();
Base* basePtr1 = new Child();
Base* basePtr2 = new Base();
}
In C++, is there any way to query the type of an object and then use that information to dynamically create a new object of the same type?
For example, say I have a simple 3 class hierarchy:
class Base
class Foo : public Base
class Bar : public Base
Now suppose I give you an object cast as type Base -- which is in reality of type Foo.
Is there a way to query the type and use that info to later create new objects of type Foo?
Clone method
There is nothing provided by the language that queries type and lets you construct from that information, but you can provide the capability for your class hierarchy in various ways, the easiest of which is to use a virtual method:
struct Base {
virtual ~Base();
virtual std::auto_ptr<Base> clone(/*desired parameters, if any*/) const = 0;
};
This does something slightly different: clone the current object. This is often what you want, and allows you to keep objects around as templates, which you then clone and modify as desired.
Expanding on Tronic, you can even generate the clone function.
Why auto_ptr? So you can use new to allocate the object, make the transfer of ownership explicit, and the caller has no doubt that delete must deallocate it. For example:
Base& obj = *ptr_to_some_derived;
{ // since you can get a raw pointer, you have not committed to anything
// except that you might have to type ".release()"
Base* must_free_me = obj.clone().release();
delete must_free_me;
}
{ // smart pointer types can automatically work with auto_ptr
// (of course not all do, you can still use release() for them)
boost::shared_ptr<Base> p1 (obj.clone());
auto_ptr<Base> p2 (obj.clone());
other_smart_ptr<Base> p3 (obj.clone().release());
}
{ // automatically clean up temporary clones
// not needed often, but impossible without returning a smart pointer
obj.clone()->do_something();
}
Object factory
If you'd prefer to do exactly as you asked and get a factory that can be used independently of instances:
struct Factory {}; // give this type an ability to make your objects
struct Base {
virtual ~Base();
virtual Factory get_factory() const = 0; // implement in each derived class
// to return a factory that can make the derived class
// you may want to use a return type of std::auto_ptr<Factory> too, and
// then use Factory as a base class
};
Much of the same logic and functionality can be used as for a clone method, as get_factory fulfills half of the same role, and the return type (and its meaning) is the only difference.
I've also covered factories a couple times already. You could adapt my SimpleFactory class so your factory object (returned by get_factory) held a reference to a global factory plus the parameters to pass to create (e.g. the class's registered name—consider how to apply boost::function and boost::bind to make this easy to use).
The commonly used way to create copies of objects by base class is adding a clone method, which is essentially a polymorphic copy constructor. This virtual function normally needs to be defined in every derived class, but you can avoid some copy&paste by using the Curiously Recurring Template Pattern:
// Base class has a pure virtual function for cloning
class Shape {
public:
virtual ~Shape() {} // Polymorphic destructor to allow deletion via Shape*
virtual Shape* clone() const = 0; // Polymorphic copy constructor
};
// This CRTP class implements clone() for Derived
template <typename Derived> class Shape_CRTP: public Shape {
public:
Shape* clone() const {
return new Derived(dynamic_cast<Derived const&>(*this));
}
};
// Every derived class inherits from Shape_CRTP instead of Shape
// Note: clone() needs not to be defined in each
class Square: public Shape_CRTP<Square> {};
class Circle: public Shape_CRTP<Circle> {};
// Now you can clone shapes:
int main() {
Shape* s = new Square();
Shape* s2 = s->clone();
delete s2;
delete s;
}
Notice that you can use the same CRTP class for any functionality that would be the same in every derived class but that requires knowledge of the derived type. There are many other uses for this besides clone(), e.g. double dispatch.
There's only some hacky ways to do this.
The first and IMHO the ugliest is:
Base * newObjectOfSameType( Base * b )
{
if( dynamic_cast<Foo*>( b ) ) return new Foo;
if( dynamic_cast<Bar*>( b ) ) return new Bar;
}
Note that this will only work if you have RTTI enabled and Base contains some virtual function.
The second an neater version is to add a pure virtual clone function to the base class
struct Base { virtual Base* clone() const=0; }
struct Foo : public Base { Foo* clone() const { return new Foo(*this); }
struct Bar : public Base { Bar* clone() const { return new Bar(*this); }
Base * newObjectOfSameType( Base * b )
{
return b->clone();
}
This is much neater.
One cool/interesting thing about this is that
Foo::clone returns a Foo*, while Bar::clone returns a Bar*. You might expect this to break things, but everything works due to a feature of C++ called covariant return types.
Unfortunately covariant return types don't work for smart pointers, so using sharted_ptrs your code would look like this.
struct Base { virtual shared_ptr<Base> clone() const=0; }
struct Foo : public Base { shared_ptr<Base> clone() const { return shared_ptr<Base>(new Foo(*this) ); }
struct Bar : public Base { shared_ptr<Base> clone() const { return shared_ptr<Base>(new Bar(*this)); }
shared_ptr<Base> newObjectOfSameType( shared_ptr<Base> b )
{
return b->clone();
}
You can use e.g. typeid to query an object's dynamic type, but I don't know of a way to directly instantiate a new object from the type information.
However, apart from the clone approach mentioned above, you could use a factory:
#include <typeinfo>
#include <iostream>
class Base
{
public:
virtual void foo() const
{
std::cout << "Base object instantiated." << std::endl;
}
};
class Derived : public Base
{
public:
virtual void foo() const
{
std::cout << "Derived object instantiated." << std::endl;
}
};
class Factory
{
public:
static Base* createFrom( const Base* x )
{
if ( typeid(*x) == typeid(Base) )
{
return new Base;
}
else if ( typeid(*x) == typeid(Derived) )
{
return new Derived;
}
else
{
return 0;
}
}
};
int main( int argc, char* argv[] )
{
Base* X = new Derived;
if ( X != 0 )
{
std::cout << "X says: " << std::endl;
X->foo();
}
Base* Y = Factory::createFrom( X );
if ( Y != 0 )
{
std::cout << "Y says: " << std::endl;
Y->foo();
}
return 0;
}
P.S.: The essential part of this code example is of course the Factory::createFrom method. (It's probably not the most beautiful C++ code, since my C++ has gone a little rusty. The factory method probably shouldn't be static, on second thought.)
I used macros in my project to synthesize such methods.
I'm just researching this approach now, so I may be wrong, but here's an answer to your question in my code of IAllocable.hh. Note that I use GCC 4.8, but I hope 4.7 suits.
#define SYNTHESIZE_I_ALLOCABLE \
public: \
auto alloc() -> __typeof__(this) { return new (__typeof__(*this))(); } \
IAllocable * __IAllocable_alloc() { return new (__typeof__(*this))(); } \
private:
class IAllocable {
public:
IAllocable * alloc() {
return __IAllocable_alloc();
}
protected:
virtual IAllocable * __IAllocable_alloc() = 0;
};
Usage:
class Usage : public virtual IAllocable {
SYNTHESIZE_I_ALLOCABLE
public:
void print() {
printf("Hello, world!\n");
}
};
int main() {
{
Usage *a = new Usage;
Usage *b = a->alloc();
b->print();
delete a;
delete b;
}
{
IAllocable *a = new Usage;
Usage *b = dynamic_cast<Usage *>(a->alloc());
b->print();
delete a;
delete b;
}
}
Hope it helps.
In C++, is there any way to query the type of an object...
Yes, use typeid() operator
For example:
// typeid, polymorphic class
#include <iostream>
#include <typeinfo>
#include <exception>
using namespace std;
class CBase { virtual void f(){} };
class CDerived : public CBase {};
int main () {
try {
CBase* a = new CBase;
CBase* b = new CDerived;
cout << "a is: " << typeid(a).name() << '\n';
cout << "b is: " << typeid(b).name() << '\n';
cout << "*a is: " << typeid(*a).name() << '\n';
cout << "*b is: " << typeid(*b).name() << '\n';
} catch (exception& e) { cout << "Exception: " << e.what() << endl; }
return 0;
}
Output:
a is: class CBase *
b is: class CBase *
*a is: class CBase
*b is: class CDerived
If the type typeid evaluates is a pointer preceded by the dereference operator (*), and this pointer has a null value, typeid throws a bad_typeid exception
Read more.....
class Base
{
public:
virtual ~Base() { }
};
class Foo : public Base
{
};
class Bar : public Base
{
};
template<typename T1, typename T2>
T1* fun(T1* obj)
{
T2* temp = new T2();
return temp;
}
int main()
{
Base* b = new Foo();
fun<Base,Foo>(b);
}
When there are extremely many classes deriving from the same base class then this code will save you from having to include clone methods every class. It's a more convenient way of cloning that involves templates and an intermediate subclass. It's doable if the hierarchy is shallow enough.
struct PureBase {
virtual Base* Clone() {
return nullptr;
};
};
template<typename T>
struct Base : PureBase {
virtual Base* Clone() {
return new T();
}
};
struct Derived : Base<Derived> {};
int main() {
PureBase* a = new Derived();
PureBase* b = a->Clone(); // typeid(*b) == typeid(Derived)
}
I am quite confused with the dynamic_cast keyword in C++.
struct A {
virtual void f() { }
};
struct B : public A { };
struct C { };
void f () {
A a;
B b;
A* ap = &b;
B* b1 = dynamic_cast<B*> (&a); // NULL, because 'a' is not a 'B'
B* b2 = dynamic_cast<B*> (ap); // 'b'
C* c = dynamic_cast<C*> (ap); // NULL.
A& ar = dynamic_cast<A&> (*ap); // Ok.
B& br = dynamic_cast<B&> (*ap); // Ok.
C& cr = dynamic_cast<C&> (*ap); // std::bad_cast
}
the definition says:
The dynamic_cast keyword casts a datum from one pointer or reference
type to another, performing a runtime check to ensure the validity of the cast
Can we write an equivalent of dynamic_cast of C++ in C so that I could better understand things?
Here's a rundown on static_cast<> and dynamic_cast<> specifically as they pertain to pointers. This is just a 101-level rundown, it does not cover all the intricacies.
static_cast< Type* >(ptr)
This takes the pointer in ptr and tries to safely cast it to a pointer of type Type*. This cast is done at compile time. It will only perform the cast if the types are related. If the types are not related, you will get a compiler error. For example:
class B {};
class D : public B {};
class X {};
int main()
{
D* d = new D;
B* b = static_cast<B*>(d); // this works
X* x = static_cast<X*>(d); // ERROR - Won't compile
return 0;
}
dynamic_cast< Type* >(ptr)
This again tries to take the pointer in ptr and safely cast it to a pointer of type Type*. But this cast is executed at runtime, not compile time. Because this is a run-time cast, it is useful especially when combined with polymorphic classes. In fact, in certain cases the classes must be polymorphic in order for the cast to be legal.
Casts can go in one of two directions: from base to derived (B2D) or from derived to base (D2B). It's simple enough to see how D2B casts would work at runtime. Either ptr was derived from Type or it wasn't. In the case of D2B dynamic_cast<>s, the rules are simple. You can try to cast anything to anything else, and if ptr was in fact derived from Type, you'll get a Type* pointer back from dynamic_cast. Otherwise, you'll get a NULL pointer.
But B2D casts are a little more complicated. Consider the following code:
#include <iostream>
using namespace std;
class Base
{
public:
virtual void DoIt() = 0; // pure virtual
virtual ~Base() {};
};
class Foo : public Base
{
public:
virtual void DoIt() { cout << "Foo"; };
void FooIt() { cout << "Fooing It..."; }
};
class Bar : public Base
{
public :
virtual void DoIt() { cout << "Bar"; }
void BarIt() { cout << "baring It..."; }
};
Base* CreateRandom()
{
if( (rand()%2) == 0 )
return new Foo;
else
return new Bar;
}
int main()
{
for( int n = 0; n < 10; ++n )
{
Base* base = CreateRandom();
base->DoIt();
Bar* bar = (Bar*)base;
bar->BarIt();
}
return 0;
}
main() can't tell what kind of object CreateRandom() will return, so the C-style cast Bar* bar = (Bar*)base; is decidedly not type-safe. How could you fix this? One way would be to add a function like bool AreYouABar() const = 0; to the base class and return true from Bar and false from Foo. But there is another way: use dynamic_cast<>:
int main()
{
for( int n = 0; n < 10; ++n )
{
Base* base = CreateRandom();
base->DoIt();
Bar* bar = dynamic_cast<Bar*>(base);
Foo* foo = dynamic_cast<Foo*>(base);
if( bar )
bar->BarIt();
if( foo )
foo->FooIt();
}
return 0;
}
The casts execute at runtime, and work by querying the object (no need to worry about how for now), asking it if it the type we're looking for. If it is, dynamic_cast<Type*> returns a pointer; otherwise it returns NULL.
In order for this base-to-derived casting to work using dynamic_cast<>, Base, Foo and Bar must be what the Standard calls polymorphic types. In order to be a polymorphic type, your class must have at least one virtual function. If your classes are not polymorphic types, the base-to-derived use of dynamic_cast will not compile. Example:
class Base {};
class Der : public Base {};
int main()
{
Base* base = new Der;
Der* der = dynamic_cast<Der*>(base); // ERROR - Won't compile
return 0;
}
Adding a virtual function to base, such as a virtual dtor, will make both Base and Der polymorphic types:
class Base
{
public:
virtual ~Base(){};
};
class Der : public Base {};
int main()
{
Base* base = new Der;
Der* der = dynamic_cast<Der*>(base); // OK
return 0;
}
Unless you're implementing your own hand-rolled RTTI (and bypassing the system one), it's not possible to implement dynamic_cast directly in C++ user-level code. dynamic_cast is very much tied into the C++ implementation's RTTI system.
But, to help you understand RTTI (and thus dynamic_cast) more, you should read up on the <typeinfo> header, and the typeid operator. This returns the type info corresponding to the object you have at hand, and you can inquire various (limited) things from these type info objects.
More than code in C, I think that an english definition could be enough:
Given a class Base of which there is a derived class Derived, dynamic_cast will convert a Base pointer to a Derived pointer if and only if the actual object pointed at is in fact a Derived object.
class Base { virtual ~Base() {} };
class Derived : public Base {};
class Derived2 : public Base {};
class ReDerived : public Derived {};
void test( Base & base )
{
dynamic_cast<Derived&>(base);
}
int main() {
Base b;
Derived d;
Derived2 d2;
ReDerived rd;
test( b ); // throw: b is not a Derived object
test( d ); // ok
test( d2 ); // throw: d2 is not a Derived object
test( rd ); // ok: rd is a ReDerived, and thus a derived object
}
In the example, the call to test binds different objects to a reference to Base. Internally the reference is downcasted to a reference to Derived in a typesafe way: the downcast will succeed only for those cases where the referenced object is indeed an instance of Derived.
First, to describe dynamic cast in C terms, we have to represent classes in C.
Classes with virtual functions use a "VTABLE" of pointers to the virtual functions.
Comments are C++. Feel free to reformat and fix compile errors...
// class A { public: int data; virtual int GetData(){return data;} };
typedef struct A { void**vtable; int data;} A;
int AGetData(A*this){ return this->data; }
void * Avtable[] = { (void*)AGetData };
A * newA() { A*res = malloc(sizeof(A)); res->vtable = Avtable; return res; }
// class B : public class A { public: int moredata; virtual int GetData(){return data+1;} }
typedef struct B { void**vtable; int data; int moredata; } B;
int BGetData(B*this){ return this->data + 1; }
void * Bvtable[] = { (void*)BGetData };
B * newB() { B*res = malloc(sizeof(B)); res->vtable = Bvtable; return res; }
// int temp = ptr->GetData();
int temp = ((int(*)())ptr->vtable[0])();
Then a dynamic cast is something like:
// A * ptr = new B();
A * ptr = (A*) newB();
// B * aB = dynamic_cast<B>(ptr);
B * aB = ( ptr->vtable == Bvtable ? (B*) aB : (B*) 0 );
The following is not really close to what you get from C++'s dynamic_cast in terms of type checking but maybe it will help you understand its purpose a little bit better:
struct Animal // Would be a base class in C++
{
enum Type { Dog, Cat };
Type type;
};
Animal * make_dog()
{
Animal * dog = new Animal;
dog->type = Animal::Dog;
return dog;
}
Animal * make_cat()
{
Animal * cat = new Animal;
cat->type = Animal::Cat;
return cat;
}
Animal * dyn_cast(AnimalType type, Animal * animal)
{
if(animal->type == type)
return animal;
return 0;
}
void bark(Animal * dog)
{
assert(dog->type == Animal::Dog);
// make "dog" bark
}
int main()
{
Animal * animal;
if(rand() % 2)
animal = make_dog();
else
animal = make_cat();
// At this point we have no idea what kind of animal we have
// so we use dyn_cast to see if it's a dog
if(dyn_cast(Animal::Dog, animal))
{
bark(animal); // we are sure the call is safe
}
delete animal;
}
A dynamic_cast performs a type checking using RTTI. If it fails it'll throw you an exception (if you gave it a reference) or NULL if you gave it a pointer.
There are no classes in C, so it's impossible to to write dynamic_cast in that language. C structures don't have methods (as a result, they don't have virtual methods), so there is nothing "dynamic" in it.
No, not easily. The compiler assigns a unique identity to every class, that information is referenced by every object instance, and that is what gets inspected at runtime to determine if a dynamic cast is legal. You could create a standard base class with this information and operators to do the runtime inspection on that base class, then any derived class would inform the base class of its place in the class hierarchy and any instances of those classes would be runtime-castable via your operations.
edit
Here's an implementation that demonstrates one technique. I'm not claiming the compiler uses anything like this, but I think it demonstrates the concepts:
class SafeCastableBase
{
public:
typedef long TypeID;
static TypeID s_nextTypeID;
static TypeID GetNextTypeID()
{
return s_nextTypeID++;
}
static TypeID GetTypeID()
{
return 0;
}
virtual bool CanCastTo(TypeID id)
{
if (GetTypeID() != id) { return false; }
return true;
}
template <class Target>
static Target *SafeCast(SafeCastableBase *pSource)
{
if (pSource->CanCastTo(Target::GetTypeID()))
{
return (Target*)pSource;
}
return NULL;
}
};
SafeCastableBase::TypeID SafeCastableBase::s_nextTypeID = 1;
class TypeIDInitializer
{
public:
TypeIDInitializer(SafeCastableBase::TypeID *pTypeID)
{
*pTypeID = SafeCastableBase::GetNextTypeID();
}
};
class ChildCastable : public SafeCastableBase
{
public:
static TypeID s_typeID;
static TypeID GetTypeID()
{
return s_typeID;
}
virtual bool CanCastTo(TypeID id)
{
if (GetTypeID() != id) { return SafeCastableBase::CanCastTo(id); }
return true;
}
};
SafeCastableBase::TypeID ChildCastable::s_typeID;
TypeIDInitializer ChildCastableInitializer(&ChildCastable::s_typeID);
class PeerChildCastable : public SafeCastableBase
{
public:
static TypeID s_typeID;
static TypeID GetTypeID()
{
return s_typeID;
}
virtual bool CanCastTo(TypeID id)
{
if (GetTypeID() != id) { return SafeCastableBase::CanCastTo(id); }
return true;
}
};
SafeCastableBase::TypeID PeerChildCastable::s_typeID;
TypeIDInitializer PeerChildCastableInitializer(&PeerChildCastable::s_typeID);
int _tmain(int argc, _TCHAR* argv[])
{
ChildCastable *pChild = new ChildCastable();
SafeCastableBase *pBase = new SafeCastableBase();
PeerChildCastable *pPeerChild = new PeerChildCastable();
ChildCastable *pSameChild = SafeCastableBase::SafeCast<ChildCastable>(pChild);
SafeCastableBase *pBaseToChild = SafeCastableBase::SafeCast<SafeCastableBase>(pChild);
ChildCastable *pNullDownCast = SafeCastableBase::SafeCast<ChildCastable>(pBase);
SafeCastableBase *pBaseToPeerChild = SafeCastableBase::SafeCast<SafeCastableBase>(pPeerChild);
ChildCastable *pNullCrossCast = SafeCastableBase::SafeCast<ChildCastable>(pPeerChild);
return 0;
}
static_cast< Type* >(ptr)
static_cast in C++ can be used in scenarios where all type casting can be verified at compile time.
dynamic_cast< Type* >(ptr)
dynamic_cast in C++ can be used to perform type safe down casting. dynamic_cast is run time polymorphism. The dynamic_cast operator, which safely converts from a pointer (or reference) to a base type to a pointer (or reference) to a derived type.
eg 1:
#include <iostream>
using namespace std;
class A
{
public:
virtual void f(){cout << "A::f()" << endl;}
};
class B : public A
{
public:
void f(){cout << "B::f()" << endl;}
};
int main()
{
A a;
B b;
a.f(); // A::f()
b.f(); // B::f()
A *pA = &a;
B *pB = &b;
pA->f(); // A::f()
pB->f(); // B::f()
pA = &b;
// pB = &a; // not allowed
pB = dynamic_cast<B*>(&a); // allowed but it returns NULL
return 0;
}
For more information click here
eg 2:
#include <iostream>
using namespace std;
class A {
public:
virtual void print()const {cout << " A\n";}
};
class B {
public:
virtual void print()const {cout << " B\n";}
};
class C: public A, public B {
public:
void print()const {cout << " C\n";}
};
int main()
{
A* a = new A;
B* b = new B;
C* c = new C;
a -> print(); b -> print(); c -> print();
b = dynamic_cast< B*>(a); //fails
if (b)
b -> print();
else
cout << "no B\n";
a = c;
a -> print(); //C prints
b = dynamic_cast< B*>(a); //succeeds
if (b)
b -> print();
else
cout << "no B\n";
}
dynamic_cast uses RTTI. It can slow down your application, you can use modification of the visitor design pattern to achieve downcasting without RTTI http://arturx64.github.io/programming-world/2016/02/06/lazy-visitor.html