views:

280

answers:

6

Hi, What does the following syntax mean?

typedef void* hMyClass; //typedef as a handle or reference
hMyClass f = &something;
const MyClass& foo = static_cast<MyClass&>(*f);
foo.bar();
+2  A: 

A static_cast means that the system does not actually try to make sure that when you are converting from one reference type to another, the thing you are converting is actually an instance of the target type (unlike dynamic casts).

Hence, you are telling the compiler that you are smart enough to know that the address which is contained in hMyClass and which came from something actually contains an instance of MyClass, and that you are taking full responsibility for the unpredictable things that will happen if you are wrong.

What is the type of your "something"? You could also have an error there. You may want a &something.

Uri
+1  A: 

This actually isn't valid. You're assigning a value to a type, not a variable on line 2.

A: 

void* is commonly used for a generic pointer.

In C# it would be similar to something like:

object o = new XmlDocument();

object o = new List();

However, in C++, there is very little type safety being enforced. IIRC, static_cast is the same as (cast), in that no run-time type checks are made.

Alan
Generally templates are used for generic collections; there are a very few places in which you actually need void-pointers these days. Void pointers are generally used for 'anonymous' types such as handles. Generally, a template based solution is preferred when applicable.
Jasper Bekkers
static_cast<> isn't quite the same as the C-style (cast). The C-style cast can function as either static_cast<>, reinterpret_cast<>, const_cast<>, or any combination depending on the situation.
Dan Olson
@Dan: I said, that no run-time checks are made, which is true. (Cast) and static_cast doest not involve RTTI.@Jasper: My example is ambiguous, i shows in C# you can assign any class to an object reference. In C++, that's what you're doing with void*, assigning any object type to a generic pointer.
Alan
A: 

Essentially, somebody has stored an MyClass pointer in a void pointer, likely passing it to callback. This code, having presumably been called back, is casting it back, to use it as a MyClass.

Also, it has syntax errors, as eagerwishes notes.

tpdi
+1  A: 

It's fairly unsafe code. Basically, this is happening:

int *pointer_to_int = new int; // create int

void *pointer_to_anything =
    reinterpret_cast<void*>(pointer_to_int); // now store it in a void*

// later

int *another_pointer =
    reinterpret_cast<int*>(pointer_to_anything); // cast it back to int

*another_pointer = 5; // set the int to 5

That last line is unsafe because a void* can point to anything. What happens when, in your code, hMyClass does not point to a MyClass object? The cast will compile, but at runtime you'll (hopefully) crash.

That said, your code does not compile as is. hMyClass is a type (void*), not a variable. You would need something like:

typedef void* hMyClass; //typedef as a handle or reference
hMyClass theHandle = /*something*/;

const MyClass& foo = *static_cast<MyClass*>(*theHandle);
foo.bar();

** EDIT **

I fixed the code above, I missed an error. Anyway, the & denotes a reference. It differs from a pointer in that a reference is just an alias to a variable, while a pointer only points. There was a thread on this recently.

To go with the integer example above:

int *pointer_to_int = new int; // create int

void *pointer_to_anything =
    reinterpret_cast<void*>(pointer_to_int); // now store it in a void*

// later
int *another_pointer =
    reinterpret_cast<int*>(pointer_to_anything); // cast it back to int

   *another_pointer = 5; // set the int to 5
// ^ this dereferences the pointer

int& int_reference = *another_pointer;
// int_reference acts just like a normal integer,
// but is an alias to the original

int_reference = 2; // same as *another_pointer = 2
int_reference = *another_pointer; // no effect: the integer is still 2.
// this is because references are only assigned on the line they are defined.
// this line is the same as *another_pointer = *another_pointer,
// which has no effect

int normal_int = *another_pointer; // has the value of 2
normal_int = int_reference; // still has a value of 2

normal_int = 100; // normal_int is 100, but int_reference/another_pointer are
// both still 2, since normal_int is not a reference or pointer to the
// original integer

*another_pointer = -1; // the original int is now -1
// and since int_reference **is** the original int, it too is now -1.
// however, normal_int is still 100

Hope that helps. More information here and here.

GMan
Edited with more information.
GMan
A: 

It's hard to say exactly what this "means" without more context. I presume you're working on someone else's code and the lines you're showing appear scattered across a number of functions.

My best guess as to the code intent is that this is a mechanism to deal with 3rd-party code/libraries. It is common in C++ to use (non-templated) 3rd-party libraries with your own types. If those libraries need to temporarily hold data that you created and own, you need a way to give the library access to your data even though the library doesn't know about your types. One example is a callback/event feature. If a library will asynchronously notify you when an event occurs, you need to give it a function pointer and also user-defined data so that when the function is called, you know what to do with it. Libraries commonly take a void* pointer for this user-supplied data. It is common in C++ to just pass in an object instance for the user-supplied data and then delegate to that object to handle the callback. Here's what the code would look like:

// 3rd-party library API
typedef void (*PingNotifyPtr)(void*);
void NotifyOnPing(PingNotifyPtr, void* userData);
// User Code
void MyNotify(void* myData)
{
   MyClass* ptr = (MyClass*)myData;
   // do something with ptr
}
void Main()
{
   MyClass *pClass = new MyClass();
   NotifyOnPing(&MyNotify, pClass);
   // the callback is now armed with all the data it needs.
}

Many libraries accomplish this by declaring "void*" arguments. This is a raw pointer to some memory location. Anything could be at that location, an integer, a class instance, a string, etc. The 3rd-party library holds onto that pointer and returns it back to your code at some point.

The 3rd line of your example code is taking the void* pointer and casting it to a reference to a class instance. C++ references are like pointers except they cannot be NULL and they use value syntax (using the '.' operator instead of the '->' operator, for example.) The 4th line of your example code then uses a method on the re-constituted class instance.

Anyway, if all 4 lines of code are consecutive in the code base you're dealing with, that code means that someone's ignorant of C++. Here's a more compact way to do the same code in one line:

((const MyClass*)something)->Foo();

or, if you prefer value syntax:

(*((const MyClass*)something)).Foo();

Good Luck!

David Gladfelter