0

我想知道是否有可能(以及是否,如何)创建一个 X 值的指针
现在,假设我知道可以在这个指针中分配哪些类型。

例如,一个 X 值的指针(当然可以随意更改这个值的名称),它可以指向 string、bool 和自定义类的变量

4

8 回答 8

8

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

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

创建根类型是可行的,但它不适用于原始类型,而且相当侵入。

A是一个变量,可以包含指向这 3 种类型(或)boost::variant< bool*, std::string*, MyClass* >中任何一种的指针。您可能会发现使用起来很有挑战性,因为它强制类型安全,而且语法会让人讨厌。boolstd::stringMyClass

同样,指向的指针boost::variant< bool, std::string, MyClass >可能是您想要的,但它不会让您指向bool您没有在胡闹的变量。

完整的 C++11 支持,union可以包含任意类型,再加上一个枚举可以让你做一些非常像boost::variant. 不利的一面是,这需要你被指出的东西是union. 无论有没有完整的 C++11 支持,指针联合都是合理的。在这两种情况下,您都必须手动跟踪类型并保持同步。

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

于 2013-01-01T16:50:43.603 回答
4

我今天学了一个新表达,所以我要用它,“这是一个XY问题”,你想做X,所以你认为解决方案是Y,所以你问怎么做Y。你可能应该问如何做 Y 代替。这有点像你发现你的汽车前轮被刺破了,你去和机械师谈谈,但你不问“我该如何修理爆胎”,你问“我如何解开车轮螺母”,而只是在您卸下所有车轮螺母并且汽车翻倒后,您是否意识到应该在汽车下方放置一个千斤顶,以便能够在汽车不会翻倒的情况下取下车轮...

当然,有 void 指针和联合,这没什么大不了的。但是,您仍然需要知道您的指针实际指向什么,否则您将一团糟。

所以一般来说,在 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; }
}
于 2013-01-01T17:03:36.647 回答
2

您可以使用指向 void的指针。

于 2013-01-01T16:48:00.633 回答
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)。

但是对于任何选项,尚不清楚这样的东西会有什么用......

于 2013-01-01T16:48:23.007 回答
1

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

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

例如:

int main()
{
    int a;

    void *x=&a;

    func(x);

    ....

}


void func(void *argument)
{

   int i=*(int *)argument;

   ....

}
于 2013-01-01T17:27:33.637 回答
0

,您不能有一个指针指向未指定类型的对象。指针的全部意义在于它指向特定类型的对象。int*x指向一个intA*a指向一个A

当然,您可以做的是拥有一个void*完全不指向任何内容的类型变量 ( void),但可以保存任何地址。如果您以某种方式记住它的地址,那么您可以使用 astatic_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不是指针:您不能使用->运算符来调用地址存储在AnyPointerWrapper::ptr;中的对象的成员函数。它只是一个包装器,您可以从中获得适当的指针。

于 2013-01-01T19:10:38.573 回答
0

您可以拥有指向任何类型(对象、指针、原始类型等)的指针,但不能拥有指向引用的指针。

于 2013-01-01T17:37:48.210 回答
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 也有 ANY 类型。
你可以在里面存储任何东西。

boost::any x = 12;
x = new CustomClass;
x = new std::string("Hi There");
x = std::string("Plop");  // even works without pointers.
于 2013-01-01T16:55:33.137 回答