Said A. Sryheni
Said A. Sryheni

Reputation: 757

C++ cast void* when not sure what the type is

how can I cast void* to another type in C++, when I'm not sure what the other type is. this is a sample of my code:

class A
{
};
class B
{
};
void main()
{
    void * p;
    if (rand() % 2)
        p = new A();
    else
        p = new B();

    A * a = NULL;
    B * b = NULL;
}

I want a code to cast the pointer p to A* if its type is A* and put the answer in a, else cast the pointer p to B* if its type is B* and put the answer in b.

I tried static_cast and regular cast, but they both cast any way without making runtime check, and even if the cast is not correct, they don't throw an exception.

Upvotes: 1

Views: 210

Answers (3)

Tomas Andrle
Tomas Andrle

Reputation: 13354

You can implement your own RTTI. Add a common base class which will require its subclasses to report their types. Then use static_cast to get the actual type.

#include <stdlib.h>


enum class Type { A, B };

class Base {
public:
    virtual Type type() const = 0;
    virtual ~Base() {}
};

class A : public Base
{
    Type type() const { return Type::A; }
};
class B : public Base
{
    Type type() const { return Type::B; }
};

int main()
{
    void * p;
    if (rand() % 2)
        p = new A();
    else
        p = new B();

    Base *base = static_cast<Base*>( p );

    A * a = NULL;
    B * b = NULL;

    if ( base->type() == Type::A ) {
        a = static_cast<A*>( base );
    } else if ( base->type() == Type::B ) {
        b = static_cast<B*>( base );
    }
}

Second option is to keep the type information outside the classes, like this:

#include <stdlib.h>

class A
{
};
class B
{
};
int main()
{
    void * p;
    bool is_a;

    if (rand() % 2) {
        p = new A();
        is_a = true;
    } else {
        p = new B();
        is_a = false;
    }

    A * a = NULL;
    B * b = NULL;

    if ( is_a ) {
        a = static_cast<A*>( p );
    } else {
        b = static_cast<B*>( p );
    }
}

Upvotes: 0

ravi
ravi

Reputation: 10733

If your classes are polymorphic then you can rest on facility provided by typeid and typeinfo(Although you'd rather use virtual functions most often). Otherwise there's no easy way to do this.

If any way you want to do it then you need to replicate that functionality. For e.g:-

template<typename T>
class TypeStoringBase
{
  private:
    enum Type { CLASS_A, CLASS_B, CLASS_C ...};
  protected:
    ~TypeStoringBase();
  public:
    ...
};

And then derive every class from this class (using private inheritance )for which you want to ensure correctness while casting.

Upvotes: 1

Neil Kirk
Neil Kirk

Reputation: 21803

If you can change the functions not to use void pointers any more, you can use some kind of "safe void pointer" replacement, along the following lines:

struct A{};
struct B{};

struct AnyBase
{
    virtual ~AnyBase() = 0;
};
inline AnyBase::~AnyBase() {}

template<class T>
struct Any : public AnyBase
{
    Any(T *p) : p(p) {}
    T *p;
};

void MaybeA(const AnyBase& p1)
{
    const Any<A> *p2 = dynamic_cast<const Any<A>*>(&p1);
    if (p2)
    {
        A *pa = p2->p;
        cout << "Is an A\n";
    }
    else
    {
        cout << "Is not A\n";
    }
}

int main()
{
    A a;
    B b;
    MaybeA(Any<A>(&a));
    MaybeA(Any<B>(&b));
}

Boost may have some perhaps tidier implementation of this. Although you will need to change all your functions, the change itself should be straightforward, and may even detect bugs you didn't know about!

Note that this solution makes no assumptions about the underlying types. They don't need to have virtual functions or be copyable.

Upvotes: 1

Related Questions