0

I have a void pointer and I would like to get the content of what the pointer refers to.

void class :: method(void * pointer)
{
     cout<<pointer; // The address which the pointer refers to.
     cout<<?; //The content of where the pointer refers to.
}  

The original type of pointer is unknown.

EDIT: The goal is to allow create a "generic method" which gets any type of argument, and do the same actions for each. The limitation is that the method is virtual and therefore I cannot use template method.

yael aviv
  • 201
  • 1
  • 5
  • 9
  • I suspect you are abusing `void*`. – John Dibling Sep 09 '14 at 12:35
  • @BasileStarynkevitch, I would like to allow sending to the method every type, and do the same actions for each. Limitation: the method is virtual and therefore I cannot use template method. Any ideas? – yael aviv Sep 09 '14 at 12:37
  • @JohnDibling, LOL! I would like to allow sending to the method every type, and do the same actions for each. Limitation: the method is virtual and therefore I cannot use template method. Any ideas? – yael aviv Sep 09 '14 at 12:39
  • 2
    Derive your classes from a common base with a pure virtual method. Pass a pointer to the base class to the function instead of void star, and call the virtual method there. – John Dibling Sep 09 '14 at 12:42
  • @JohnDibling, misunderstood. Would appreciate if you can post an example – yael aviv Sep 09 '14 at 12:46
  • What is your whole software supposed to do? Is it homework? Or some kind of interpreter? – Basile Starynkevitch Sep 09 '14 at 13:16

2 Answers2

3

You need to cast the void* back to its original type (ie. before it was cast to void*). Then you can dereference the pointer and use what it's pointing to.

Eg. :

void fun(void* ptr) {
    int* iptr = (int*) ptr;
    std::cout << *iptr;
}

int* iptr = new int(42);
fun(iptr);

One way to do this in a way that fits your specific use case, is to pass on the type information with the object using a generic type like boost::any :

#include <iostream>
#include <string>
#include <boost/any.hpp>

class Foo {
    public :
    virtual void fun(const boost::any& obj) {
        if (typeid(int) == obj.type()) {
            std::cout << boost::any_cast<int>(obj) << std::endl;
        }
        else if (typeid(std::string) == obj.type()) {
            std::cout << boost::any_cast<std::string>(obj) << std::endl;
        }
        else {
            std::cout << "unsupported type" << std::endl;
        }
    }
};

int main(void) {
    Foo foo;
    int i = 42;
    std::string s = "str";
    float f = 1.1f;
    foo.fun(i);
    foo.fun(s);
    foo.fun(f);
    return 0;   
}

But that can get very verbose, depending on how many types you want to support.

Sander De Dycker
  • 16,053
  • 1
  • 35
  • 40
  • Thanks. And if I do not know what is the original type and cannot use templates? – yael aviv Sep 09 '14 at 12:23
  • 2
    @yaelaviv: Then redesign your program so you can find the original type, or don't convert to `void*` in the first place. There's simply no way to identify what `void*` points to. – Mike Seymour Sep 09 '14 at 12:25
  • 1
    @yaelaviv : then you have a problem. You cannot safely dereference the `void*` pointer if you don't know its original type. – Sander De Dycker Sep 09 '14 at 12:26
  • @SanderDeDycker, What if I know that the pointer is string or integer, is there a solution? – yael aviv Sep 09 '14 at 12:35
  • @yaelaviv : you need to know the exact type, not a vague description. If you update your question with a bit of background info on what it is that you're trying to achieve, we'll probably be able to assist you better. – Sander De Dycker Sep 09 '14 at 12:41
1

This is impossible. The types in C++ are (mostly) a compile-time property. At runtime, types are unknown (they are erased).

However, RTTI exist, notably for instances of some class containing virtual methods.

There is no possible trick in general. You could redesign your program by having some kind of variant type, or by having a common root class from which all your objects inherit, etc etc, or by using union types (better have your own discriminated unions).

Put it another way: when the compiler see a void* pointer, it does not even know the size of the data pointed by that pointer.

Future C++ standards might propose some std::any container.

Maybe you could have something like a cheap discriminated union class like

class Int_or_String {
   const bool isint;
   union {
     int n;
     std::string s;
   };
   Int_or_String(const int i) : isint(true), n(i) {};
   Int_or_String(const std::string &st): isint(false), s(st) {};
   ~Int_or_String() { if (isint) n=0; else 
     /*not sure*/ s.std::string::~std::string(); };
   // much more is missing
};

I'm not even sure of the syntax to explicitly destroy a union member.

See e.g. this question on calling destructors explicitly

Perhaps the Qt object model might inspire you. Look also into its QVariant

The usual way is to define a root class in your program and adopt the convention that all your objects are inheriting this root class (or even that all your meaningful data are in objects derived from that root class). This requires a redesign of the whole thing.

So you would decide that your root class is e.g

class Root {
public:
  virtual void out(std::ostream&s) =0;
  virtual ~Root() =0;
  /// other common methods
};

static inline std::ostream& operator << (std::ostream&o, const Root &r)
   { r.out(o); return o; }


class Integer : public Root {
   const int num;
 public:
   Integer(int n) : Root(), num(n) {};
   void out (std::ostream &o) { o << num ; }; 
   /// etc...
 }; // end class Num


class String : public Root {
   const std::string str;
 public:
   String(const std::string& s) : Root(), str(s) {};
   void out (std::ostream &o) { o << str ; }; 
   /// etc...
 }; // end class String
Community
  • 1
  • 1
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • @BasileStarykevitch, any trick? Can't I force the content to be converted to any type? The method is indeed virtual, can you please give an example? – yael aviv Sep 09 '14 at 12:28
  • @BasileStarykevitch, Thanks, If I know that the pointer is string or ineger, is there a solution? – yael aviv Sep 09 '14 at 12:34