当前位置:  开发笔记 > 编程语言 > 正文

在C++中存储任意对象的列表

如何解决《在C++中存储任意对象的列表》经验,为你挑选了4个好方法。

在Java中,您可以拥有一个对象列表.您可以添加多种类型的对象,然后检索它们,检查它们的类型,并对该类型执行适当的操作.
例如:(如果代码不完全正确,我会道歉)

List list = new LinkedList();

list.add("Hello World!");
list.add(7);
list.add(true);

for (object o : list)
{
    if (o instanceof int)
        ; // Do stuff if it's an int
    else if (o instanceof String)
        ; // Do stuff if it's a string
    else if (o instanceof boolean)
        ; // Do stuff if it's a boolean
}


在C++中复制此行为的最佳方法是什么?



1> j_random_hac..:

boost::variant类似于dirkgently的建议boost::any,但支持Visitor模式,这意味着以后更容易添加特定于类型的代码.此外,它在堆栈上分配值而不是使用动态分配,从而导致稍微更高效的代码.

编辑:正如litb在评论中指出的那样,使用variant而不是any手段,您只能从预先指定的类型列表中保存值.这通常是一种力量,尽管这可能是提问者案件中的一个弱点.

这是一个例子(虽然不使用访客模式):

#include 
#include 
#include 

using namespace std;
using namespace boost;

...

vector > v;

for (int i = 0; i < v.size(); ++i) {
    if (int* pi = get(v[i])) {
        // Do stuff with *pi
    } else if (string* si = get(v[i])) {
        // Do stuff with *si
    } else if (bool* bi = get(v[i])) {
        // Do stuff with *bi
    }
}

(是的,你应该在技术上使用vector::size_type而不是int用于i类型,你应该在技术上vector::iterator反而使用,但我试图保持简单.)



2> Ferruccio..:

您使用Boost.Variant和访问者的示例:

#include 
#include 
#include 
#include 

using namespace std;
using namespace boost;

typedef variant object;

struct vis : public static_visitor<>
{
    void operator() (string s) const { /* do string stuff */ }
    void operator() (int i) const { /* do int stuff */ }
    void operator() (bool b) const { /* do bool stuff */ }      
};

int main() 
{
    list List;

    List.push_back("Hello World!");
    List.push_back(7);
    List.push_back(true);

    BOOST_FOREACH (object& o, List) {
        apply_visitor(vis(), o);
    }

    return 0;
}


使用这种技术的一个好处是,如果稍后,您将另一种类型添加到变体中,并且您忘记修改访问者以包含该类型,则它将无法编译.你必须支持每一种可能的情况.然而,如果您使用switch或cascading if语句,很容易忘记在任何地方进行更改并引入错误.



3> dirkgently..:

C++不支持异类容器.

如果你不打算使用boosthack就是创建一个虚拟类,并让所有不同的类派生自这个虚拟类.创建一个您选择的容器来容纳虚拟类对象,您就可以开始了.

class Dummy {
   virtual void whoami() = 0;
};

class Lizard : public Dummy {
   virtual void whoami() { std::cout << "I'm a lizard!\n"; }
};


class Transporter : public Dummy {
   virtual void whoami() { std::cout << "I'm Jason Statham!\n"; }
};

int main() {
   std::list hateList;
   hateList.insert(new Transporter());
   hateList.insert(new Lizard());

   std::for_each(hateList.begin(), hateList.end(), 
                 std::mem_fun(&Dummy::whoami));
   // yes, I'm leaking memory, but that's besides the point
}

如果您打算使用boost,可以试试boost::any.这是一个使用的例子boost::any.

您可能会找到两位感兴趣的C++专家撰写的这篇优秀文章.

现在,boost::variant作为j_random_hacker提到的另一件事是要注意的.所以,这里有一个比较,以了解使用什么.

使用boost::variant上面的代码看起来像这样:

class Lizard {
   void whoami() { std::cout << "I'm a lizard!\n"; }
};

class Transporter {
   void whoami() { std::cout << "I'm Jason Statham!\n"; }
};

int main() {

   std::vector< boost::variant > hateList;

   hateList.push_back(Lizard());
   hateList.push_back(Transporter());

   std::for_each(hateList.begin(), hateList.end(), std::mem_fun(&Dummy::whoami));
}



4> David Thornl..:

这种事情多久经常有用?我已经用C++编程了很多年,在不同的项目上,从来没有真正想要一个异类容器.由于某些原因,它在Java中可能很常见(我的Java经验要少得多),但是对于Java项目中任何给定的使用,可能有一种方法可以做一些在C++中更好的工作.

C++比Java更重视类型安全,这是非常类型不安全的.

也就是说,如果对象没有任何共同点,为什么要将它们存储在一起?

如果他们确实有共同点,那么你可以为他们做一个继承的课程; 或者,使用boost :: any.如果它们继承,则具有要调用的虚函数,或者如果你真的必须使用dynamic_cast <>.

推荐阅读
360691894_8a5c48
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有