如何在具有不同参数类型的对象中同时使用向量?

时间:2017-09-13 16:37:41

标签: c++ templates pointers vector

我目前希望有一个对象向量,其中每个对象具有不同的属性。

预期结果:

//v is a vector
v.push_back(ttSaveObj(5, "int example"));
v.push_back(ttSaveObj("Hello, world!", "string example"));

std::cout << v[0].data << " " << v[0].variableName << std::endl; //Intended Output: 5 int example
std::cout << v[1].data << " " << v[1].variableName << std::endl; //Intended Output: Hello, world! string example

基于this answer我尝试在模板中使用<void*>的类构造函数,但这似乎只是创建一个指向void的指针(正如我部分预期的那样)。 / p>

ttSaveObj.hpp:

template <typename T>
class ttSaveObj {
  public:

    ttSaveObj(T pVar, std::string pName) {
      data = pVar;
      variableName = pName;
    };
    ~ttSaveObj() {};

    std::string variableName;
    T data;
};

ttGameObj.hpp:

#include "ttSaveObj.hpp"

class ttGameObj {
  public:

    ttGameObj();
    ~ttGameObj();
    std::vector<ttSaveObj<void*>> data;
};

ttGameObj.cpp:

#include "ttGameObj.hpp"

ttGameObj::ttGameObj() {
  int asdf = 5;
  int * test = &asdf;
  data.push_back(ttSaveObj<void*>(test, "X"));
  std::cout << &data[0].data << " " << data[0].variableName << std::endl; //Output: 0x15fb770 X
}

任何有助于我更接近我的预期结果的事情都表示赞赏,谢谢!

3 个答案:

答案 0 :(得分:5)

您在向量中放置的对象似乎有两个数据成员:variableName,其类型为固定std::string,而data字段为不同类型。

您可以考虑对variant字段使用C++17's std::variant(或Boost&#39; data实施)。例如,如果您计划为int支持floatstd::stringdata类型,则可以使用std::variant<int, float, std::string>

还有std::any,如果您想存储任何类型的实例(满足std::any documentation中描述的要求)。

现代 C ++中,我建议避免使用C风格的void*,并且只在必要时使用它(例如,如果你处于某个传统的C API边界) :有更安全,更强大和更高级别的替代品。

另一个选项(如果它对您的设计更有意义)是为要放入向量中的对象定义基类(接口),并定义实现此接口的自定义类。在这种情况下,我建议使用 smart 指针(例如std::unique_ptrstd::shared_ptr)以简单安全的方式管理这些对象(我在这里看到另一个使用raw的答案)指针,需要明确的new / delete - 实际上在该代码中有new但没有delete,导致资源泄漏。)

E.g:

#include <iostream>
#include <memory>
#include <string>
#include <vector>
using namespace std;

// Interface for an element to be inserted in the vector
class IElement
{
public:
    IElement() {}
    virtual ~IElement() {}

    virtual string ToString() = 0;

    // Other virtual methods ...
};

class IntElement : public IElement
{
public:
    explicit IntElement(int n) : _n{ n } {}

    virtual string ToString() override
    {
        return to_string(_n);
    }

private:
    int _n;
};

class StringElement : public IElement
{
public:
    explicit StringElement(const string& s) : _s{ s } {}

    virtual string ToString() override
    {
        return _s;
    }

private:
    string _s;
};

int main() 
{
    vector<shared_ptr<IElement>> elements;
    elements.push_back(make_shared<IntElement>(10));
    elements.push_back(make_shared<IntElement>(20));
    elements.push_back(make_shared<StringElement>("Hello"));
    elements.push_back(make_shared<StringElement>("World"));

    for (const auto& e : elements)
    {
        cout << e->ToString() << '\n';
    }
}

输出:

10
20
Hello
World

答案 1 :(得分:0)

如果您使用的是C ++ 11,则可以使用标准库中的元组类。你可以像这样制作这个对象:

auto v = std::make_tuple(ttSaveObj(5, "int example"), ttSaveObj("Hello, world!", "string example"))
std::cout << std::get<0>(v).data << " " << std::get<0>(v).variableName << std::endl;

虽然访问索引是模板参数,但是有一个缺点,因此必须在编译时知道,这意味着您无法遍历元素。此外,必须在编译时知道元组中元素的类型。

答案 2 :(得分:0)

如果我正确地理解了你的目标,就可以采用类似Java的方法,但是你应该将矢量包装成永不忘记清理。

// Example program
#include <iostream>
#include <string>
#include <vector>
#include <string.h>
#include <memory>

using std::vector;

class Object 
{
public:

    explicit Object() {}
    virtual ~Object() {}

    virtual const char* toString() const = 0;

};

class StringObject : public Object
{
public:
    explicit StringObject(const char* string) : Object()
    {
        if(string != 0)
        {
            m_value = new char[strlen(string) + 1];
            strcpy(((char*)m_value), string);
        } else
        {
            m_value = new char[1];
            m_value[0] = 0;
        }
    }
    virtual ~StringObject()
    {
        delete m_value;
    }


    virtual const char* toString() const
    {
        return (const char*)m_value;   
    }
private:
    char* m_value;
};

class IntObject : public Object
{
public:
    explicit IntObject(int val) : Object()
    {
        m_value = val;
    }
    virtual ~IntObject()
    {
    }


    virtual const char* toString() const
    {
        return std::to_string(m_value).c_str();
    }
private:
    int m_value;
};

int main()
{

    auto vec = vector<std::unique_ptr<Object>>();
    vec.push_back(std::make_unique<IntObject>(9));
    vec.push_back(std::make_unique<IntObject>(11));
    vec.push_back(std::make_unique<StringObject>("hello"));
    vec.push_back(std::make_unique<StringObject>("world"));

    for(const auto& v : vec)
    {
        std::cout << v.get()->toString() << " ";
    }

}

按预期输出&#34; 9 11你好世界&#34;。