2010-04-30 59 views
2

我已经清楚地一直停留在Java的土地太久...是否有可能做下面的Java代码的C++相当于:C++泛型列表分配

interface Foo {} 

class Bar implements Foo {} 

static List<Foo> getFoo() { 
    return new LinkedList<Foo>(); 
} 

static List<Bar> getBar() { 
    return new LinkedList<Bar>(); 
} 

List<? extends Foo> stuff = getBar(); 

其中foo是一个子类酒吧。

所以在C++ ....

std::list<Bar> * getBars() 
{ 
    std::list<Bar> * bars = new std::list<Bar>; 
    return bars; 
} 

std::list<Foo> * stuff = getBars(); 

希望是有道理....

+1

您确定这适用于Java吗?因为我刚刚检查过,并不是因为Java不支持协变泛型。此外,这只有在Bar'是Foo的子类时才有意义。 – 2010-04-30 12:15:05

+0

正确。我的错。我现在纠正了代码片段。 – S73417H 2010-04-30 16:14:49

回答

3

没有在我的意见,在C++中没有意义。

首先你返回一个不存在的引用。为了避免这种情况,你可以通过你的std ::列表作为基准参数的功能进行修改,如

void fillFoos(std::list<Foo> & foos) 

其次,FOOS不是吧,不能复制另一个人,除非我想如果你提供正确的复制操作符。

但是,如果你使用继承,你所有的foos和bars都应该是指针(如果你可以从boost或tr1中以shared_ptr指针的方式创建智能指针)。但是,这并不意味着复制品的作品。

我不确定你想做什么,但是在这种情况下从JAVA转换到C++不起作用。如果你创建foos,他们会自动获得一切。

std::list<Foo> foos; // just work fine 

如果你想构建为FOOS的酒吧名单:

std::list< Bar * > bars; 
bars.push_back(new Foo()); 

或者像我会把它在真正的C++代码的shared_ptr:

typedef boost::shared_ptr<Bar>; 
typedef boost::shared_ptr<Foo>; 
typedef std::list<BarPtr> BarList; 

BarList bars; 

bars.push_back(FooPtr(new Foo())); 
1

一切除了你微细返回参照局部变量。它被保存在堆栈中并在函数返回后被释放。

+0

好吧,我迷路了。我只是尝试了他的Java并且是C++代码,并且都不起作用。这两种语言都没有协变泛型/模板,所以这应该如何工作?! – 2010-04-30 12:11:59

+0

@ Space_C0wb0y - 我刚才意识到他有Foo和Boo ......这不应该,你是对的 – Andrey 2010-04-30 12:34:33

2

你需要的对象为这些行动提供支持的构造函数,所以你不应该返回refernce,而将要复制的直线物体,否则返回一个指针,即:

std::list<Bar> getBars() 
{ 
    std::list<Bar> Bars; 
    return Bars; 
} 

std::list<Bar>* getBars() 
{ 
    return new std::list<Bar>(); 
} 

的std ::列表支持复制另一个列表的对象,但前提是该列表是同一类型,即:你不能从std::list<Bar>复制到std::list<Foo>含蓄,但你可以复制从std::list<Foo>std::list<Foo>

+0

你会怎么做? – Snake 2010-04-30 11:33:26

+0

被警告,这几乎肯定会导致内存泄漏。 – 2010-04-30 12:11:00

+0

是的,如果你不小心的话,最好的办法就是将它包装在一个智能/共享指针中,所以当它不再使用时会自动删除 – Necrolis 2010-05-01 05:13:47

4

变化

std::list<Bar> & getBars() 

std::list<Bar> getBars() 

这将通过价值原则的回报,但有拷贝构造eliding机制,优化编译器应该能够优化

std::list<Bar> bars (getBars()); 

到不涉及复制构造函数,只是直接构建bars

另外,在C++ 0x中有移动构造函数,所以即使复制/移动因为任何原因没有消失,上面的代码也是有效的。

编辑错过的子问题:

一般来说,这是不可能在C干净做++(我假设Foo超的Bar,否则你在做什么意义不大) 。它可能有一些reinterpret_cast黑魔法,但我强烈建议不要这样做。

最接近大概是这样的(与getBars()相应调整):

std::list <Bar*> bars (getBars()); 
std::list <Foo*> foos (bars.begin(), bars.end()); 

然而,这不会对您的一些不平凡的存储管理负担。使用某种自动指针可能会有所帮助,但据我记忆,只有shared_ptr可以在容器中使用。

最后,Foo/Bar类层次结构应该使用虚拟函数,否则你想要做的事情几乎肯定不会起作用。除非你真的想忽略子类中的任何覆盖)。

+0

-1,因为你没有回答作者的问题, std :: list 'to'std :: list '。 – 2010-04-30 12:10:16

+0

@ Space_C0wb0y:对,我错过了这个问题。编辑涵盖了它,尽管它没有提供直接的答案。 – doublep 2010-04-30 12:40:49

+0

删除了downvote。但是我仍然想知道为什么没有人看到这在Java中甚至不起作用。 – 2010-04-30 12:50:31

0

此外,新的std :: list将返回一个指针,而不是引用。

2

无论我得到的东西这里完全错误,或者你的Java代码不起作用。我刚刚尝试过。它不起作用。原因是,Java中的通用容器are not covariant(这意味着,如果BarFoo的子类,它也不起作用)。其次,如果FooBar的子类,则可以将Foo的引用分配给Bar,但不能以其他方式(Java或C++)。

C++中的容器也不是协变的。但是你可以做

std::list<Foo*> FooList; 
// fill FooList; 
std::list<Bar*> BarList(FooList.begin(), FooList.end()); 

如果FooBar一个子类。但是,这会产生FooList中的所有指针都被复制到BarList中的效果。这意味着,如果您之后通过添加或删除元素来更改FooList,这些更改将不会反映在BarList中。