6
class BASE {
public:
    virtual ~BASE() {}
    void lamp() {
        cout << "\nBASE CLASS";
    }
};

class DERIVED : public BASE {
public:
    void fun();
};

void DERIVED::fun() {
    cout << "\nDERIVED CLASS!";
}

int main() {

    BASE * pbase = new DERIVED; //BASE CLASS POINTER
    void * vbase = pbase;       //VOID POINTER TAKING BASE POINTER 
    DERIVED * pder;             //DERIVED CLASS POINTER

    //pder = static_cast<DERIVED *>(vbase);  //THIS WORKS
    pder = dynamic_cast<DERIVED *>(vbase);   //THIS DOESN'T
    pder->lamp();
    pder->fun();

    return 0;
}

Whenever I try to dynamically cast the void* pointer to the derived class pointer, I get the following error:

cannot dynamic_cast 'vbase' (of type 'void*') to type 'class DERIVED*' (source is not a pointer to class)

I've searched StackOverflow and followed advice by implementing a virtual function in the base class to avoid the error. What am I doing wrong? Is this possible at all?

My overall intention is to cast ANY incoming Object type into a Derived class type using a void* pointer. I hope you understand what I mean.

For example:

void dynamicCast(void * vptr)
{
    BASE * pbase = new DERIVED;
    DERIVED * pder;

    pder = dynamic_cast<DERIVED *>(vbase);
}

I should be able to pass any type of pointer to the dynamicCast function and it should be converted to the derived class pointer.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • What you're asking for is fundamentally impossible. Why are you trying to do this? Perhaps there's another way to achieve that. –  Aug 30 '17 at 01:59
  • The answer is: you don't. – Sam Varshavchik Aug 30 '17 at 02:02
  • `void *` pointer cannot be safely cast to `BASE *` or `DERIVED *` because they are not related. You cannot use `static_cast` or `dynamic_cast` for this purpose. – Zamrony P. Juhara Aug 30 '17 at 02:03
  • @hvd This is an assignment given to me. I have to implement a various linked list functionalities using an header file. The function declarations are in the header and the definitions are in a separate .cpp file. The function to Insert a new Node must take a void pointer as the user can give any-type of object as a Node with varying number of members in the file with main() function. i hope you understand what I'm trying to say. TL:DR. 3 Files: A header to hold function declarations, a .cpp file to definitions for the functions and another .cpp file where the functions are implemented. – Vignesh Gunasekaran Aug 30 '17 at 02:03
  • @VigneshGunasekaran Sounds like you don't need to cast at all, sounds like you can just leave it a `void *`. –  Aug 30 '17 at 02:05
  • 2
    You can store a void * in a list, you don't need to cast it to anything. You need a class to store the void * – Garr Godfrey Aug 30 '17 at 02:05
  • @GarrGodfrey But I get an error when I try to access the values stored in the memory location. ** Left of -> must point to a Class/Struct/Union/generic Type** – Vignesh Gunasekaran Aug 30 '17 at 02:09
  • That is a different bug. – drescherjm Aug 30 '17 at 02:11
  • then don't do that. – Garr Godfrey Aug 30 '17 at 02:11
  • @GarrGodfrey So Is it impossible to implement a generic linked list which can take any type of object? – Vignesh Gunasekaran Aug 30 '17 at 02:12
  • 1
    no, it's easy. you just cannot spy on the data passed to you. don't use the void* as a node, it is data attached to the node. – Garr Godfrey Aug 30 '17 at 02:13

4 Answers4

4

I think there is a design or/and comprehension problem

As explained you can not dynamic_cast from a void*.

Why? Because dynamic_cast needs some Run-Time Type Information (RTTI) to do the cast (see this link for further details). From void* alone, the C++ code has no chance to know where this information is. The minimum is to use a pointer to an object having such RTTI information.

This information is created and bounded to any class having at least one virtual method. If there is no virtual method this information is not included. That is the reason why this does not work:

struct A
{
};

struct B : A
{
};

int main()
{
  B  b;
  A *a = &b;

  dynamic_cast<B *>(a);  // YOUR COMPILE TIME ERROR
}

A fix is to add a virtual method to A. Here I have added a virtual destructor as this is generally a good thing

struct A
{
   virtual ~A() = default;
};

struct B : A
{
};

int main()
{
  B  b;
  A *a = &b;

  dynamic_cast<B *>(a);  // OK
}

Also note that dynamic_cast allows you to check that the conversion was legal.

For instance we can add a C class and check:

struct C 
{
};

int main()
{
  B  b;
  A *a = &b;

  assert(dynamic_cast<B *>(a)!=nullptr); // OK
  assert(dynamic_cast<C *>(a)==nullptr); // OK can not cast A to C 
}

This kind of run-time operations are not free. If you search for maximum speed to can use this trick:

assert(dynamic_cast<B *>(a)!=nullptr);
B* b=static_cast<B*>(a);

In debug mode you will check if everything is ok and in release mode with the -DNDEBUG flag to remove the assert you will only use the static_cast

Picaud Vincent
  • 10,518
  • 5
  • 31
  • 70
2

When you convert a pointer to an object type into a pointer to void, the only valid conversion for that void pointer is back to its original type. You can't use dynamic_cast on a pointer to void because void is not a polymorphic type, so you do it with a static_cast. Like this:

BASE *pbase = new DERIVED;
void *vbase = pbase; // Ok; implicit conversion to void*
BASE *pbase1 = static_cast<BASE*>(vbase); // the cast is required

Once you've gotten back the pointer to BASE, of course, you can use dynamic_cast to convert it to a pointer to the derived type:

DERIVED *pder = dynamic_cast<DERIVED*>(pbase1);
Pete Becker
  • 74,985
  • 8
  • 76
  • 165
1

You cannot use dynamic_cast on a void *.

From the specification, for dynamic_cast<T>(v):

If T is a pointer type, v shall be a prvalue of a pointer to complete class type, and the result is a prvalue of type T. ...

What you should do is to let all your classes derive from the same polymorphic base class (which has at least one virtual function) BASE, and use BASE * instead of void *.

fefe
  • 3,342
  • 2
  • 23
  • 45
  • This is an assignment given to me. I have to implement a various linked list functionalities using an header file. The function declarations are in the header and the definitions are in a separate .cpp file. The function to Insert a new Node must take a void pointer as the user can give any-type of object as a Node with varying number of members in the file with main() function. i hope you understand what I'm trying to say. TL:DR. 3 Files: A header to hold function declarations, a .cpp file to definitions for the functions and another .cpp file where the functions are implemented. – Vignesh Gunasekaran Aug 30 '17 at 02:10
  • Do you need to access the void * in your linked list, or only the user of the linked list need to know about what it inside the void *? – fefe Aug 30 '17 at 02:13
  • But void *vbase = pbase. It has the Base pointer right? or Am i wrong? – Vignesh Gunasekaran Aug 30 '17 at 02:14
  • If your linked list needs to access some functions inside the void *, then put them in a base class and every thing inherits from that base. You cannot use void * here and must use the base *. If not, the user of list needs to keep track of the void * and use the appropriate cast to cast it back. but not dynamic_cast. – fefe Aug 30 '17 at 02:15
  • I need to access the void * in my Linked list but what type of object it points to is decided by the user. – Vignesh Gunasekaran Aug 30 '17 at 02:16
  • 1
    Type information is very important in C++, using void * you lost it. They may have the same internal value, but the behavior is different. – fefe Aug 30 '17 at 02:16
  • If you do not know what type of object it is, how can you access it? What if it is just a int * or char *? – fefe Aug 30 '17 at 02:17
  • The Node object must be a class or a struct and they can carry varying number of members. The reason i tried to use void pointer in he first place was to accommodate for the varying number of members. For example, first node is a class containing 3 members and the second is a different struct object containing two members and I should be able to insert the created node seamlessly. – Vignesh Gunasekaran Aug 30 '17 at 02:22
  • What ever your intention is, casting to void loses type information. And there will be no way to check what type it originally is. Void * can be cast to a pointer to class types using static_cast, but you must make sure that they are actually the same type yourself. C++ cannot prevent any error introduced by the cast. – fefe Aug 30 '17 at 02:32
1

Your generic linked list should be like this:

class Node
{
    Node* next;
    void* vdata;
}

That's the only data structure strictly required, but you might want a circular list, or a base node to keep track of the end of the list, or a doubly-linked list.

Caller passes you a void*, you create a new node, set "vdata" and add the node to your list.

Garr Godfrey
  • 8,257
  • 2
  • 25
  • 23