C++:如何将派生类的容器传递给需要其基类的容器的函数?
你好!有人知道如何使下面代码中的“chug(derlist);
”行起作用吗?
#include <iostream>
#include <list>
using namespace std;
class Base
{
public:
virtual void chug() { cout << "Base chug\n"; }
};
class Derived : public Base
{
public:
virtual void chug() { cout << "Derived chug\n"; }
void foo() { cout << "Derived foo\n"; }
};
void chug(list<Base*>& alist)
{
for (list<Base*>::iterator i = alist.begin(), z = alist.end(); i != z; ++i)
(*i)->chug();
}
int main()
{
list<Base*> baselist;
list<Derived*> derlist;
baselist.push_back(new Base);
baselist.push_back(new Base);
derlist.push_back(new Derived);
derlist.push_back(new Derived);
chug(baselist);
// chug(derlist); // How do I make this work?
return 0;
}
我需要这个的原因基本上是,我有一个非常复杂的对象的容器,我需要将其传递给某些只关心这些复杂对象中的一两个虚拟函数的函数。
我知道简短的答案是“你不能”,我真的在寻找人们用来解决这个问题的任何技巧/习惯用法。
提前致谢。
HI! Anyone know how I can make the line "chug(derlist);
" in the code below work?
#include <iostream>
#include <list>
using namespace std;
class Base
{
public:
virtual void chug() { cout << "Base chug\n"; }
};
class Derived : public Base
{
public:
virtual void chug() { cout << "Derived chug\n"; }
void foo() { cout << "Derived foo\n"; }
};
void chug(list<Base*>& alist)
{
for (list<Base*>::iterator i = alist.begin(), z = alist.end(); i != z; ++i)
(*i)->chug();
}
int main()
{
list<Base*> baselist;
list<Derived*> derlist;
baselist.push_back(new Base);
baselist.push_back(new Base);
derlist.push_back(new Derived);
derlist.push_back(new Derived);
chug(baselist);
// chug(derlist); // How do I make this work?
return 0;
}
The reason I need this is basically, I have a container of very complex objects, which I need to pass to certain functions that only care about one or two virtual functions in those complex objects.
I know the short answer is "you can't," I'm really looking for any tricks/idioms that people use to get around this problem.
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
你的问题很奇怪;主题问“如何在不丢失多态性的情况下将项目放入容器中” - 但这是回避问题;容器中的项目不会失去多态性。您只需拥有一个基本类型的容器即可,一切正常。
从您的示例来看,您所问的问题似乎是“如何将子指针的容器转换为基指针的容器?” - 答案是,你不能。子指针可以转换为基指针,而子指针的容器则不能。它们是不相关的类型。不过,请注意,shared_ptr可以转换为shared_ptr,但这只是因为它们有额外的魔力来实现这一点。容器没有这样的魔力。
一个答案是使 chug 成为一个模板函数(免责声明:我没有在带有编译器的计算机上,所以我没有尝试编译它):
然后 chug 可以采用任何类型的任何容器,只要它是一个容器指针并有一个 chug 方法。
Your question is odd; the subject asks "how do I put items in a container without losing polymorphism" - but that is begging the question; items in containers do not lose polymorphism. You just have a container of the base type and everything works.
From your sample, it looks what you're asking is "how do I convert a container of child pointers to a container of base pointers?" - and the answer to that is, you can't. child pointers are convertible to base pointers, containers of child pointers are not. They are unrelated types. Although, note that a shared_ptr is convertible to shared_ptr, but only because they have extra magic to make that work. The containers have no such magic.
One answer would be to make chug a template function (disclaimer: I'm not on a computer with a compiler, so I haven't tried compiling this):
Then chug can take any container of any type, as long as it's a container of pointers and has a chug method.
要么通过指针存储它们(boost::shared_ptr是一个流行的选项),要么使用Boost ptr_containers在内部存储指针,但在外部提供一个很好的API(当然还有全自动删除)。
容器的多态转换根本不可能,因此始终传递 ptr_vector
Either store them by pointer (boost::shared_ptr is a popular option), or use Boost ptr_containers that store pointers internally, but offer a nice API on the outside (and of course fully automated deletion).
Polymorphic conversions of containers are simply not possible, so always pass a ptr_vector<Base>& and downcast in the function itself.
为什么不让 chug 成为一个基于模板的函数,这样它就可以拥有基本类型和派生类型的实例?
或者,为了获得更好的解决方案,您可以使用
std::for_each
。Why not make chug a template based function so it can have instances for base and derived types?
Or, for a better solution you can use
std::for_each
.也许您可以使
chug
成为一个模板函数,将模板参数转换为Base*
类型,然后调用chug
。Maybe you can make
chug
a template function that casts the template parameter to aBase*
type, then callschug
on that.