【问题标题】:Storing a type in C++在 C++ 中存储类型
【发布时间】:2010-04-01 17:04:52
【问题描述】:

是否可以将类型名称存储为 C++ 变量?例如,像这样:

type my_type = int; // or string, or Foo, or any other type
void* data = ...;
my_type* a = (my_type*) data;

我知道在 99.9% 的情况下,有更好的方法来做你想做的事,而无需求助于强制转换 void 指针,但我很好奇 C++ 是否允许这种事情。

【问题讨论】:

  • 这是不可能的。取决于您要实现的具体目标,但模板可能是可行的。你能告诉我们更多关于你要解决什么问题的背景吗?
  • 在 c++0x 中该特定功能是可能的,但从来没有一个地方有用,因为当原始变量存在时类型信息会丢失。
  • 我能想到的在 C++ 中多态存储类型的唯一方法是 类型擦除

标签: c++ casting types


【解决方案1】:

不,这在 C++ 中是不可能的。

RTTI typeid 运算符允许您在运行时获取有关类型的一些信息:您可以获取类型的名称并检查它是否等于另一个类型,仅此而已。

【讨论】:

  • 这个名字是不可移植的。
  • 它是可移植的,只是不能在编译器之间。在 linux 上使用 GCC 编译的应用程序将具有与 Windows 上的 GCC 相同的类型名称,但与 VS 编译器不同。
  • @Thomas 这是en.cppreference.com/w/cpp/types/type_info 你说的接线员吗?这不是运营商,对吧?而是一个存储 typeid() 结果的类?
  • 我失败了。这是typeid。正在编辑...(11 票赞成,没有人提到这个明显的错误),感谢您的发现!
【解决方案2】:

不像写的那样,但你可以做类似的事情......

class Type
{
    public:
        virtual ~Type(){}
        virtual void* allocate()const=0;
        virtual void* cast(void* obj)const=0;
};

template<typename T> class TypeImpl : public Type
{
      public:
         virtual void* allocate()const{ return new T; }
         virtual void* cast(void* obj)const{ return static_cast<T*>(obj); }
};

// ...
Type* type = new TypeImpl<int>;
void* myint = type->allocate();
// ...

这种东西可以根据你需要的功能进行扩展。

【讨论】:

  • 嗨,迈克尔。我和你的 sn-p 差不多了。派生类中的强制转换函数在您的代码中返回一个 void 指针。如何获得所需的 T*?
  • 如果你知道对象是正确的类型,你可以在调用者中显式。然而,在任何类型上操作的反射 API 都不能合理地拥有强类型方法;一般类型表示的方法需要对弱类型对象进行操作(void* 与类型的某些记录结合使用)。
  • 方法cast在这里实现了什么?它只返回一个 void* 指针,该指针必须显式地指向特定类 static_cast&lt;T*&gt; 才能使用。
【解决方案3】:

您无法在 C++ 中执行此操作,但您可以使用 boost 任何库,然后测试它所拥有的类型。示例:

bool is_int(const boost::any & operand)
{
  return operand.type() == typeid(int);
}

http://www.boost.org/doc/libs/1_42_0/doc/html/any/s02.html

【讨论】:

  • 酷,我以前没见过。
  • Boost 不是魔法,如果他们能用 C++ 做到,你也可以用 C++ 做到,这可能并不容易。
【解决方案4】:

不,您不能根据需要直接存储类型,但您可以存储类型的名称。

const char* str = typeid(int).name();

我想每当您计划使用该变量进行比较时,您可以改为将 str 变量与类型中的 name() 进行比较。

const char* myType = typeid(int).name();

//....

//Some time later:
if(!strcmp(myType, typeid(int).name()))
{
  //Do something
}

More info available here

【讨论】:

  • 除了 name() 不保证跨平台相同!
  • @Michael:我不建议将其保存到文件中
【解决方案5】:

是的,如果你自己编码的话。

enum Foo_Type{
    AFOO,
    B_AFOO,
    C_AFOO,
    RUN
};

struct MyFoo{
    Foo_Type m_type;
    Boost::shared_ptr<Foo> m_foo;
}

如下所述,我遗漏的是所有这些“foo”类型都必须与 Foo 相关。 Foo 本质上就是你的界面。

【讨论】:

  • 严格来说,不能保证 'shared_pointer' 足够大以存储所有这些不同的类型,除非 'Foo' 以某种方式与它们相关。此外,“_AFOO”是非法标识符。
  • 及时记录并修复。我将添加关于“Foo”的 cmets
  • 您根本不需要Foo,只需使用适当的删除器即可使用boost::shared_ptr&lt;void&gt;
【解决方案6】:

今天我在编码时遇到了类似的问题:
我需要在实现它的具体类的调用函数上存储多态数据类型(这里称为 refobj)。我需要一个不显式转换变量的解决方案,因为我需要减少代码量。

我的解决方案(但我还没有测试过)看起来类似于之前的答案。实际上是一个实验性的解决方案。看起来是这样的……

// interface to use in the function

class Type   
{
public:
    virtual void* getObj()const=0;
};

// here the static_cast with the "stored" type

template<typename T> class TypeImpl : public Type
{
public:
    TypeImpl(T *obj) {myobj=obj;}
    virtual void* getObj()const{ return static_cast<T*>(myobj); }

private: 
    T* myobj;
};

// here the type that will contain the polimorific type
// that I don't want to cast explicitly in my code
Type *refobj;

// here the "user code "
void userofTypes()
{
    ( refobj->getObj() ).c_str(); 
    // getObj() should return a string type over which
    // calling string concrete functions ...let's try!
}

void main()
{
    refobj=new TypeImpl < string > ( new string("hello") );
    userofTypes();
}
// it might seem absurd don't cast refobj explicitly, but of
// course there are situation in which it can be useful!

【讨论】:

    【解决方案7】:

    类型不是 C++ 中的对象(例如,它们在 Ruby 中),因此您不能存储类型的实例。实际上,类型永远不会出现在执行代码中(RTTI 只是额外的存储空间)。

    根据您的示例,您似乎正在寻找 typedef。

    typedef int Number;
    Number one = 1;
    Number* best = (Number*) one;
    

    注意 typedef 不是存储类型;它是别名类型。

    【讨论】:

    • Number 不是变量,也就是说,它的含义不能在运行时改变。
    • 注明。不过,根据他的例子,我认为他实际上并不是在寻找存储空间。
    • 你是对的,我的示例没有做 typedef 不能做的任何事情,但我最终希望存储类型(例如,作为类的成员)。很抱歉造成混乱。
    • 更好的方法是using Number = int;
    【解决方案8】:

    更好的方法是拥有一个包含加载方法的通用基类,以及加载器的接口。这将允许程序的其他部分在不知道后代类的情况下一般地加载数据:

    struct Load_Interface;
    
    struct Loader
    {
      virtual void visit(Load_Interface&) = 0;
    }
    
    struct Load_Interface
    {
      virtual void accept_loader(Loader& l)
        {
            l.visit(*this);
        }
    };
    

    这种设计避免了了解对象类型的需要。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-05
      • 1970-01-01
      • 2011-04-16
      相关资源
      最近更新 更多