是否有可能指向任何类型的变量?

时间:2013-01-01 16:45:43

标签: c++ pointers

我想知道是否有可能(以及如果,如何)创建X值的指针
现在,假设我知道在这个指针中可以分配哪些类型
例如,一个X值的指针(当然可以随意改变这个值的名称),它可以指向string,bool和一个自定义类的变量

8 个答案:

答案 0 :(得分:8)

通常你所描述的是一个坏主意。

void*适用于作品的边际价值。它抛弃了所有类型的安全性,要求你跟踪它。

创建一种根类型的作品,但它不适用于原始类型,而且相当具有侵入性。

boost::variant< bool*, std::string*, MyClass* >是一个变量,可以包含指向这3种类型中的任何一种的指针(boolstd::stringMyClass)。您可能会发现使用它具有挑战性,因为它强制执行类型安全,并且语法会变得烦人。

同样地,指向boost::variant< bool, std::string, MyClass >的指针可能就是您想要的,但它不会让您指向您不会愚弄的bool变量。

在完全支持C ++ 11的情况下,union可以包含任意类型,并且枚举可以让您执行与boost::variant非常相似的操作。作为一个缺点,这需要你指向的是union。无论是否支持完整的C ++ 11,指针联合都是合理的。在这两种情况下,您都必须手动跟踪类型并保持同步。

你真正需要考虑的是“我为什么要问这个?”,因为和许多问题一样,动机很重要。你可能没有问正确的问题。

答案 1 :(得分:4)

我今天学到了一个新表达,所以我打算用它,“这是一个XY问题”,你想做X,所以你认为解决方案是Y,所以你问如何做Y.你可能应该问如何改为Y.这有点像你发现你的汽车前轮被刺破了,你去跟机械师谈谈,但是你不会问“我该如何修理穿刺”,你会问“如何拆卸一个轮子”,只有在你拆下所有的车轮并且汽车倒下之后你是否意识到你应该在汽车下面放一个千斤顶以便能够在没有汽车摔倒的情况下关闭车轮......

当然,有无效的指针和工会,这没什么大不了的。但是,你仍然需要知道你的指针实际指向的是什么,否则你会有血腥的混乱。

所以一般来说,在C ++中,你可能不应该这样做。

你应该做的是将你的“东西”包装在另一个对象中,它知道内容是什么,并且可以处理它。这样,你没有其他东西维持状态,对象是什么以及如何使用它。

例如,我们可以这样:

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; }
}

答案 2 :(得分:2)

您可以使用pointer to void

答案 3 :(得分:1)

如果你想要一个只能用于指向这三种类型的指针,那么我会看到三个选项:

  1. 为从某个基类派生的每种类型创建一个包装类:

    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. 创建智能指针类,重载带有bool *String *Custom *的赋值运算符,并重载*运算符(尽管如此)我会做的,我不知道!)

  3. 使用变体类(例如boost::variant)。

  4. 但是对于任何选项,目前尚不清楚这样的事情会如何有用......

答案 4 :(得分:1)

void*具有指向任何数据类型的属性。它实际上用作容器或cubboard,您可以在其中放置任何数据类型的变量,然后将void*传递给函数。

您必须知道所传递数据的数据类型才能使用它。

例如:

int main()
{
    int a;

    void *x=&a;

    func(x);

    ....

}


void func(void *argument)
{

   int i=*(int *)argument;

   ....

}

答案 5 :(得分:0)

如果您事先知道类型,并且它们没有构造函数。然后你可以使用联盟。

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也有任何类型 您可以在其中存储任何内容。

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

答案 6 :(得分:0)

你可以有一个指向任何类型(对象,指针,基元类型等​​)的指针,但你不能有一个指向引用的指针。

答案 7 :(得分:0)

您不能指针指向未指定类型的对象。指针的重点是它指向特定类型的对象。 int*x指向int的{​​{1}},A*a点。

当然,你可以做的是拥有一个A类型的变量,它根本不指向任何地方(void*),但可以保存任何地址。如果你以某种方式记住它的地址,那么你可以使用void转换为适当的指针。或者,您可以使用static_cast<>在运行时查找您的dynamic_cast<>是否指向给定类型。这可以按如下方式实施

void*

并像这样使用

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;
};

(您可以添加更多功能,包括对int X; AnyPointerWrapper a; assert(a.is_null()); a = &X; assert(a.is<int>()); int*p = a.pointer<int>(); 指针的支持)。然而,注意const并非微不足道,即会导致一些性能损失。另请注意,dynamic_cast<>不是指针:您不能使用AnyPointerWrapper运算符来调用其地址存储在->中的对象的成员函数;它只是一个包装器,您可以从中获得适当的指针。