P.K.
P.K.

Reputation: 825

Are pointers to any kind of variables possible?

I would like to know if it'd be possible (and if, how) to create a pointer of X value
Now, let's say I know which types would be possible to be assigned in this pointer.

For example, a pointer of X value (of course feel free to change the name of this value), that'd be able to point to variables of string, bool and a custom class

Upvotes: 0

Views: 184

Answers (8)

Walter
Walter

Reputation: 45424

NO you cannot have a pointer pointing at objects of unspecified type. The whole point of a pointer is that it points at objects of specific type. int*x points at an int, A*a points at an A.

What you can do, of course, is to have a variable of type void* that points at nothing at all (void), but can hold any address. If you somehow remember what it is the address of, then you can use a static_cast<> to cast to an appropriate pointer. Alternatively, you can use dynamic_cast<> to find out at run-time whether your void* points to a given type. This could be implemented as follows

struct AnyPointerWrapper
{
  struct null_pointer {};
  struct wrong_pointer_type {};

  AnyPointerWrapper() : ptr(0) {}

  AnyPointerWrapper(AnyPointerWrapper const&) = default;

  AnyPointerWrapper&operator=(AnyPointerWrapper const&) = default;

  template<typename T>
  explicit AnyPointerWrapper(T*p)
  : ptr(p) {}

  template<typename T>
  AnyPointerWrapper&operator=(T*p)
  { ptr=p; return*this; }

  bool is_null() const
  { return ptr==0; }

  template<typename T>
  bool is() const
  { return dynamic_cast<T*>(ptr) != 0; }

  template<typename T>
  T* pointer()
  {
     if(p==0) throw null_pointer;
     T*p = dynamic_cast<T*>(ptr);
     if(p==0) throw wrong_pointer_type;
     return p;
  }

private:
  void*ptr;
};

and used like this

int X;
AnyPointerWrapper a;
assert(a.is_null());
a = &X;
assert(a.is<int>());
int*p = a.pointer<int>();

(you can add more functionality including support for const pointers). Note, however, that the dynamic_cast<> is not trivial, i.e. incurs some performance penalty. Note also that AnyPointerWrapper is not a pointer: you cannot use the -> operator to call a member function of the object whose address is stored in AnyPointerWrapper::ptr; it is merely a wrapper from which you can get an appropriate pointer.

Upvotes: 0

fatma.ekici
fatma.ekici

Reputation: 2827

You can have a pointer to any type (object, pointer, primitive type etc.) but you can not have a pointer to a reference.

Upvotes: 0

Alfred
Alfred

Reputation: 1663

void* has the property to point to any data type. It actually works as a container or cubboard in which you put your variable of any data type and then pass the void* to a function.

You must know the data type of the data you passed, in order to use it.

For Example:

int main()
{
    int a;

    void *x=&a;

    func(x);

    ....

}


void func(void *argument)
{

   int i=*(int *)argument;

   ....

}

Upvotes: 1

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275385

Usually what you describe is a bad idea.

void* works, for marginal values of works. It throws out all type safety, requiring you to keep track of it.

Creating a root type sort of works, but it doesn't work for primitive types, and is rather intrusive.

A boost::variant< bool*, std::string*, MyClass* > is a variable that can contain a pointer to any one of these 3 types (bool, std::string or MyClass). You will probably find it challenging to use, because it enforces type safety, and the syntax can get annoying.

Similarly, a pointer to boost::variant< bool, std::string, MyClass > may be what you want, but it doesn't let you point to bool variables you aren't fooling around with.

With full C++11 support, union can contain arbitrary types, together with an enum can let you do something very much like a boost::variant. As a downside, this requires the thing you be pointed to be a union. With or without full C++11 support, a union of pointers is reasonable. In both cases, you'll have to track the type manually and keep it in sync.

What you really need to think about is "why am I asking this?", because as with many questions, the motivation matters. You may not be asking the right question.

Upvotes: 8

Mats Petersson
Mats Petersson

Reputation: 129364

I learned a new expression today, so I'm going to use it, "This is an XY question", You want to do X, so you think the solution is Y, therefore you ask how to do Y. You PROBABLY should ask how to do Y instead. It's a bit like you find your front wheel on the car punctured, and you go talk to the mechanic, but you don't ask "how do I fix a puncture", you ask "How do I undo a wheelnut", and only after you've removed all wheelnuts and the car has fallen over do you realize that you should have put a jack under the car to be able to get the wheel off without the car falling over...

Sure, there are void pointers and unions, that's no big deal. However, you still need to know what your pointer is actually pointing at, otherwise you'll have bloody mess.

So generally, in C++, you probably shouldn't do that.

What you should do is wrap your "thing" in another object, that knows what the content is, and can handle it. That way, you don't have some other thing maintainng state of what the object is and how to use it.

For example, we can have this:

class AnyThing
{
   public:
     virtual ~AnyThing();
     virtual std::string ToString() = 0; 
     ... // other things you want to do with your "things". 
};

class IntThing: public AnyThing 
{
     private:
        int value;

     public:
        virtual std::string ToString() { ... convert int to string ... }
};

class StringThing : public Anything
{
    private: 
       std::string value;
    public:
        virtual std::string ToString() { return value; }
}

Upvotes: 4

Loki Astari
Loki Astari

Reputation: 264381

If you know the types before hand and they do not have constructors. Then you can use a union.

class CustomClass {};
union MyType
{
    char const*  a;
    bool         b;
    float        c;
};

MyType    stuff;
MyType*   ptrToStuff = &stuff;

int main()
{
    ptrToStuff->a = "Plop";
    ptrToStuff->b = false;
    ptrToStuff->c = 12.0;
}

Boost also has an ANY type.
You can store anything in it.

boost::any x = 12;
x = new CustomClass;
x = new std::string("Hi There");
x = std::string("Plop");  // even works without pointers.

Upvotes: 0

Oliver Charlesworth
Oliver Charlesworth

Reputation: 272487

If you want a pointer that can only be used to point at those three types, then I see three options:

  1. Create a wrapper class for each type that derives from some base-class:

    class Thingy { protected: Thing() {} };
    
    class BoolThingy   : public Thingy { bool x; }
    class StringThingy : public Thingy { String x; }
    class CustomThingy : public Thingy { Custom x; }
    
    ...
    
    Thingy *p = new BoolThingy;
    
  2. Create a smart-pointer class, overloading assignment operators that take bool *, String *, Custom *, and also overloading the * operator (although what that would do, I don't know!)

  3. Use a variant class (e.g. boost::variant).

But with any of the options, it's not clear how such a thing would be useful...

Upvotes: 1

user1118321
user1118321

Reputation: 26355

You can use a pointer to void.

Upvotes: 2

Related Questions