我显然已经在Java领域停留了太长时间......是否有可能使用以下Java代码的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是Bar的子类。
所以在C ++ ....
std::list<Bar> * getBars()
{
std::list<Bar> * bars = new std::list<Bar>;
return bars;
}
std::list<Foo> * stuff = getBars();
希望有道理......
答案 0 :(得分:4)
更改
std::list<Bar> & getBars()
到
std::list<Bar> getBars()
这原则上会按值返回,但是有复制构造的删除机制,所以优化编译器应该能够优化
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
类层次结构应该使用虚函数,否则你想要做的几乎肯定不会起作用(即除非你真的想忽略子类中的任何覆盖)
答案 1 :(得分:3)
我认为在C ++中没有意义。
首先,您返回不再存在的引用。为避免这种情况,您可以将std :: list作为参考参数传递给函数,如
void fillFoos( std::list< Foo > & foos )
其次,foos不是条形图,不能相互复制,除非我认为你提供了正确的复制操作符。
但是如果你使用继承,你所有的foos和bar应该是指针(如果你可以聪明的那些作为来自boost或tr1的shared_ptr指针)。但这并不意味着副本有效。
我不确定你想做什么,但在这种情况下从JAVA转换到C ++是行不通的。如果你创建了foos,它们将自动拥有条形图。
std::list< Foo > foos; // just work fine
如果你想要一个构造为foos的条形列表:
std::list< Bar * > bars;
bars.push_back( new Foo() );
或者正如我将它放在带有shared_ptr的实际C ++代码中一样:
typedef boost::shared_ptr< Bar >;
typedef boost::shared_ptr< Foo >;
typedef std::list< BarPtr > BarList;
BarList bars;
bars.push_back( FooPtr( new Foo() ) );
答案 2 :(得分:2)
你需要对象支持那些操作的构造函数,所以你不应该返回一个引用,而是一个将被复制的直接对象,否则返回一个指针,即:
std::list<Bar> getBars()
{
std::list<Bar> Bars;
return Bars;
}
或
std::list<Bar>* getBars()
{
return new std::list<Bar>();
}
std :: list支持复制另一个列表的对象,但仅当该列表属于同一类型时,即:您无法隐式地从std::list<Bar>
复制到std::list<Foo>
,但您可以从std::list<Foo>
至std::list<Foo>
。
答案 3 :(得分:2)
要么我在这里得到完全错误,要么你的Java代码不起作用。我刚试过它不起作用。原因是,Java are not covariant中的通用容器(这意味着,如果Bar
是Foo
的子类,它也不起作用)。其次,如果Foo
是Bar
的子类,那么您可以为Foo
分配Bar
个引用,但不能相反(在Java和C ++中都没有)。
C ++中的容器也不是协变的。但你可以做到
std::list<Foo*> FooList;
// fill FooList;
std::list<Bar*> BarList(FooList.begin(), FooList.end());
如果Foo
是Bar
的子类。但是,这会导致FooList
中的所有指针都被复制到BarList
中。这意味着,如果您之后通过添加或删除元素更改FooList
,则这些更改将不会反映在BarList
中。
答案 4 :(得分:1)
除了返回对局部变量的引用外,一切都很好。它保存在堆栈中,并在函数返回后释放。
答案 5 :(得分:0)
此外,新的std :: list将返回一个指针,而不是一个引用。