【问题标题】:Storing various types in a vector在向量中存储各种类型
【发布时间】:2012-12-15 16:01:56
【问题描述】:

我正在尝试将各种不同类型的数据存储在数组或向量中。到目前为止,我通过使用一个基类来做到这一点,该基类将作为指向每个对象的指针存储在向量中,然后进行类型转换以获取数据。这对 int 非常有效,但任何其他类型的数据都会引发访问冲突异常。

对不起,如果我的解释不是很好,这是我的 cmets 代码,希望对您有所帮助:

//Base class
class MenuProperty
{
private:
    std::string Name;

public:
    MenuProperty(std::string Name) : Name(Name) {};
    ~MenuProperty() {};

    std::string GetName();

};

//Typed class used to store data
template<class T>
class TMenuProperty : public MenuProperty
{
private:
    T Data;

public:
    TMenuProperty(std::string Name, T Data) : MenuProperty(Name), Data(Data) {};

    T GetData()
    {
       return this->Data;
    }
};

//Class with no type and data pointer to retrieve data
class cpMenuProperty : public MenuProperty
{
private:
    VOID* Data;

public:
    cpMenuProperty(std::string Name) : MenuProperty(Name) {};

    VOID* GetPointer()
    {
       return this->Data;
    }
};

希望这有点道理,这是我的测试代码:

int main()
{
    TMenuProperty<double> fP("Test2", 33.7354); //Create instance of property

    MenuProperty* fMP = &fP;                    //Make a pointer to the object

    cpMenuProperty* Test;                       //Make a pointer to the retrieving
                                                //object

    std::vector<MenuProperty*>              Vec;
    std::vector<MenuProperty*>::iterator    it;

    Vec.push_back(fMP);                         

    it = Vec.begin();

    Test = static_cast<cpMenuProperty*>(*it);   //Cast the first object in the list 
                                                //list to the same type as the
                                                //retrieveing object


    double Data = *(double*)Test->GetPointer(); //Dereference and access, this is
                                                //where the exception is thrown

    std::cout << Data;



    int Ret;
    std::cin >> Ret;
}

我可能在这里犯了一些重大错误,但感谢您花时间阅读到目前为止 :) 感谢您提供任何帮助,以及建设性的批评!

【问题讨论】:

标签: c++ class object types vector


【解决方案1】:
 #include<iostream>
 #include<vector>
 #include<iterator>
 #include<memory>
 class base {
 public:
 virtual void foo(){
      std::cout << "in base" << std::endl;
  }
 };

 class derived : public base {
 public:
 virtual void foo(){
      std::cout << "in derived" << std::endl;
   }
 };

 int main()
 {
    std::vector<std::unique_ptr<base>> vec;
    vec.emplace_back(new derived);
    static_cast<derived*>(vec[0].get())->foo();
    return 0;
  }

经典示例,使用现代实践。

【讨论】:

    【解决方案2】:

    您正在初始化堆栈上的 TMenuProperty 对象,然后将其转换为 cpMenuProperty。 cpMenuProperty 中永远不会为 void* 数据分配任何内存。 TMenuProperty 和 cpMenuProperty 之间没有关系,只是它们派生自同一个类。这种设计永远行不通。

    • 摆脱所有的 void*。这是自找麻烦。
    • 除非你 100% 知道自己在做什么,否则不要使用 static_cast。使用 dynamic_cast,它会告诉你转换无效(我猜你试过这个,但后来又回到 static_cast 来强制代码至少编译:))
    • 为什么不一直使用 TMenuProperty?这种方法应该行得通。
    • 如需了解其他实现方式,请查看 boost::variant 和 boost::any。
    • 如果你很勇敢并且真的知道你在做什么(没有冒犯,但我认为你没有资格这样做),并且如果你需要包装的数据类型在内存布局方面足够统一,您也许可以使您的代码使用适当的内存填充设置并以某种方式强制内存对齐。但是,无论多么不可能,我都无法想出 任何 场景来找到这样做的理由。因此,从这篇文章中我可以看出,我只能建议删除 cpMenuProperty 并仅使用抽象基类/模板派生类方法。

    【讨论】:

    • 嗯,理论上是强制类型转换将允许 void* 指针落在存储在 TMenuProperty 中的数据的开头。感谢您花时间解释这种方法的缺点。我会重新考虑这个
    • 呃,想想,我什至不需要使用cpMenuProperty的方法。很抱歉浪费了时间,在发帖之前应该多考虑一下。
    猜你喜欢
    • 1970-01-01
    • 2013-06-21
    • 2016-01-30
    • 2017-01-01
    • 1970-01-01
    • 2021-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多