• 全部
  • 问答

STL容器能否包含多态类型,如果可以的话,怎样才能做到安全有效?

anrxhzh 2002-04-12 02:45:04
希望定义一个容器能够包含整个类层次中的所有非抽象类的对象。
...全文
105 点赞 收藏 21
写回复
21 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
anrxhzh 2002-04-12
我又搞错了,shared_ptr<T>中的T可以为抽象基类,它只是要求T的析构函数必须为public。

在类工厂模式下析构函数为protected或者private是很常见的,在那种情况下就需要其他方法了,我想那时使用http://www.xraylith.wisc.edu/~khan/software/stl/STL.newbie.html#pointer_deriv 上的方法就显得很自然了,类工厂和容器的例子在More Effective C++ Item 25上也有论述。

好了,终于可以告一段落了,谢谢大家的帮忙。



回复
anrxhzh 2002-04-12
to babysloth(小懒虫虫) :

非常感谢你的解答,我想你是对的。看来我把这个问题理解错了,这不是一个多态的问题,而是一个管理指针的问题。其实就算什么都不想,直接把指针放到容器里,也不会在多态上造成问题,因为所有跟多态有关的实现细节都已经被编译器藏到了指针里,我真是杞人忧天。

真正的问题出现如何对容器中的指针进行管理上,假如直接把指针放到容器里,然后在进行删除元素操作和容器的析构器中释放元素指向的内存,听起来似乎井井有条,但是如果一个容器中有多个元素指向同一个对象或者多个指向同一个对象的元素被包含到多个容器中,就会带来一片混乱。

那么用标准库中的auto_ptr来管理指针又会如何呢?情况可能会更糟,不但老问题不能解决,还带来了新问题,auto_ptr只是简单的将指针的管理权在对象之间转移,假如在对容器进行操作的算法中将元素的管理权交给了临时对象,那么当算法完成后临时对象将自动地释放该元素指向的内存,结果将不堪设想。

终于轮到shared_ptr登场了,这个比auto_ptr复杂得多的东东管理的是对象的引用计数,当计数为0时自动释放内存,呵呵,真是个好管家。

上面啰嗦了这么多,主要是给自己看,不把它写出来我始终觉得脑子很乱。

言归正传,shared_ptr<T>要求T不能为抽象基类并且能够访问T的析构函数,这就造成了绝大多数基类不能被使用。

革命尚未成功,同志还须努力。
回复
挺拔的劲松 2002-04-12
应该保存指针才行吧!
回复
babysloth 2002-04-12
问题复杂的原因是被我们搞复杂了。
问题本身是简单的。
stl容器的设计者还没笨到连这个问题都没考虑。

对于我上面那段代码
for(list_type::iterator i = ll.begin(); i != ll.end(); ++i)
i->InterfaceOfBase();
也是多态调用。

shared_ptr是对指针的包装!
回复
babysloth 2002-04-12
2 anrxhzh
您恐怕还没明白我写的那段代码
那里面储存的是指针,何来类型丢失???
回复
anrxhzh 2002-04-12
我估计是要使用Abstract Factory之类的重型武器了。
回复
anrxhzh 2002-04-12

babysloth(小懒虫虫) 的方法是有问题的,原因在于容器认为其包含所有对象都是基类对象,这样肯定会造成类型丢失,这就是Scott Meyers所讲的Never treat arrays polymorphically 。


我把问题详细地描述一下:
存在一个单根的类层次,基类为抽象类Base。

要求实现容器类Container,满足一下要求:
1.可以包含所有非抽象的子类对象。
2.Container不必知道类层次的具体结构,也不必知道Base的接口。
3.对容器对象进行操作不能造成类型丢失。

客户可以编写这样的代码:
void Test(Container& c)
{
for(Container::iterator i(c.begin());i<c.end();++i)
(*i).InterfaceOfBase();
}
全部的奥妙在于对InterfaceOfBase的调用是多态的。
回复
babysloth 2002-04-12
这段代码在gcc、vc、bcc里都没有问题。
2 prototype
好象不是限制模板参数的问题吧^_^
回复
babysloth 2002-04-12
列代码出来吧,呵呵,看看是不是这个意思

#include <list>
#include <boost/shared_ptr.hpp>
class A{};
class C: public A{};

int main()
{
typedef boost::shared_ptr<A> element_type;
typedef std::list<element_type> list_type;

list_type ll;
ll.push_back(element_type(new C));
}
回复
prototype 2002-04-12
to anrxhzh(百宝箱):

i read the other posts and realized my understanding of your problem might be different than the others's.

here is my understanding:

you have:

class A;
class B : public A;
class C : public B;

template <typename T>
class container;

you want that 'T' should only be allowed to be 'A', 'B', 'C', not any other types.

if this is your problem ...
回复
babysloth 2002-04-12
呵呵,抱歉,没看清楚。
shared_ptr不只是解决共享的问题,事实上,这里也没有这个问题。
我的意思是,把基类的指针放进shared_ptr,再把shared_ptr作为容器放进容器就可以了。
回复
anrxhzh 2002-04-12
希望大家看看已有的解决方案,应该有启发意义。
http://www.xraylith.wisc.edu/~khan/software/stl/STL.newbie.html#pointer_deriv
回复
neccui 2002-04-12
你没理解我的意思。
我的意思是, 一个给定参数的容器里面的对象大小是固定的。
回复
anrxhzh 2002-04-12
to babysloth(小懒虫虫):

shared_ptr 解决的是共享对象的问题,而不是多态的问题,这是两个完全不同的问题,仅依靠模板肯定是不能解决多态问题的。
回复
babysloth 2002-04-12
容器要求大小固定?不是吧?
回复
neccui 2002-04-12
容器虽然不是数组,但是也是要求大小固定的,这个就没法解决。
回复
babysloth 2002-04-12
用boost库里的shared_ptr包装好,直接往容器里放就可以了。
这也是boost:shared_ptr设计的初衷之一。
回复
anrxhzh 2002-04-12
to afsfop:
我明白多态容器将带来很多麻烦,但是有时确实需要它,就像多重继承一样。容器!=数组,所以应该不存在Scott Meyers所讲的限制。我在
http://www.xraylith.wisc.edu/~khan/software/stl/STL.newbie.html#pointer_deriv
上找到了两种实现方法,可惜都需要修改类层次的现有接口,不知道有没有更完美的解决方案。

to prototype:
希望能详细地讲一下,多谢。
回复
boyfling 2002-04-12
http://www.csdn.net/expert/topic/639/639286.xml?temp=8.961123E-02
回复
prototype 2002-04-12
one way for takling this problem is to use typelist and static assertion (+ a little bit template meta-programming knowledge).

another is to use typetraits (maybe better?).
回复
相关推荐
发帖
C语言
创建于2007-09-28

6.3w+

社区成员

C语言相关问题讨论
申请成为版主
帖子事件
创建了帖子
2002-04-12 02:45
社区公告
暂无公告