我在使用继承和STL列表库时遇到问题......
说,我有一个带有两个派生类的抽象基类(其中定义了所有比较运算符)。该列表声明为
list<StoreItem*> items;
我正在插入一个名为Food或Clothing的派生类(抽象基类StoreItem)。我创建了一个即将插入的新StoreItem指针:
StoreItem* item = new Food(arguments here);
现在,我想将这个新项目(按顺序)插入到列表中,我的尝试是这样的:
list<StoreItem*>::iterator iter;
for (iter = inventory.begin(); iter != inventory.end(); iter++)
{
if (*item < **iter)
break; // break out to insert
}
inventory.insert(iter, item);
我有什么问题吗?另外,我如何从库存中提取信息? (例如:使用复制构造函数的食物tempFruit(** iter))。
提前谢谢!祝你有个美好的一天。
答案 0 :(得分:1)
如果您定义了StoreItem::operator<
,这将有效,但还有另一种方法可能会更好一点。 STL已经冷落了。您可以为<
定义StoreItem*
,然后使用list<...>::sort()
。
(你可能已经想过定义你自己的SortedItemList
类来处理内部的排序。)
是的,tempMovie(**iter)
除了其他方式外还可以使用。
修改:
我想我过早谈到从库存中抽出一些东西。这有效:
list<StoreItem *>::iterator citr = items.begin();
Food *fp = dynamic_cast<Food *>(*citr);
Food ff(*fp);
请注意,您必须知道此StoreItem*
实际指向Food
- 如果它指向Clothing
,您将会出现细分错误或更糟。要找到答案,您可以实现自己的StoreItem::whatTypeAmI()
,或使用C ++的运行时类型识别:
#include <typeinfo>
...
Food a;
StoreItem *sp = *citr;
if(typeid(*sp)==typeid(a))
{
// it's a Food
}
(请注意,您可以使用StoreItem*
或StoreItem&
做很多事情而不知道它的类型 - 多态性是您的朋友。)
答案 1 :(得分:1)
您假设您从列表中提取的项目是Food
个实例;但是,编译器不知道这一点。当您从列表中的项目(具有明显类型Food
的项目)构造StoreItem
的新实例时,您尝试调用Food::Food(const StoreItem)
或兼容的内容。为什么?因为迭代器指向StoreItem*
,可以是StoreItem
对象的实例,或者是从StoreItem
派生的任何类的实例,例如{{ 1}}。
正如其他海报所评论的那样,多态性是 成功的关键。你真的需要知道这个项目是Food
吗?如果没有,则访问所有商店项目共享的界面(如价格,序列号等)。如果您需要了解有关该项目的具体信息,那么您可以尝试推断其类型:
Food
答案 2 :(得分:0)
如果可以将两个指针之间的比较运算符定义到基类,则无需编写任何其他代码即可获得有序集合。根据您的应用程序,您可能需要一个集合或堆,甚至可能需要一个映射。这是成功的习惯......(基础是从字符串公开派生的。)
template<>
struct std::less<base*>
{
bool operator()(const base* lhs, const base* rhs) const
{
return *lhs < *rhs;
}
};
typedef set<base*> S;
int _tmain(int argc, _TCHAR* argv[])
{
base able(std::string("able"));
base baker(std::string("baker"));
base charlie(std::string("charlie"));
S inventory;
inventory.insert(&charlie);
inventory.insert(&able);
inventory.insert(&baker);
for (S::iterator i = inventory.begin(); i != inventory.end(); ++i)
std::cout << **i << endl;
return 0;
}
输出:
能够
贝克
查理
在发现这个成语之前,可以碾磨一段时间。发生了什么事情,你是专门为图书馆模板std :: less for T = base *;然后,就像使用magic一样插入std :: set(或其他有序容器)的默认比较器参数。
答案 3 :(得分:0)
您可以诉诸boost::ptr_list
而不是自制任何解决方案。如果您打算在STL中存储像容器这样的指针,它会让生活变得更容易。然后,您只需要为要插入的任何项目定义operator<
。请注意,ptr_list
并非旨在与共享所有权一起使用。要实现此目的,请在std::shared_ptrS
中使用std::list
,并为std::less
类型使用shared_ptr
。
答案 4 :(得分:0)
使用为StoreItem
指针定义的比较函数,您可以缩短插入代码,如下所示:
bool less_ptr( const StoreItem*& lhs, const StoreItem*& rhs )
{
return *lhs < *rhs;
}
插入:
StoreItem* item = new Food(arguments here);
inventory.insert( std::upper_bound( inventory.begin(), inventory.end(), item, less_ptr ), item);
std::upper_bound
(#include <algorithm>
)假设您的列表已排序,因此如果您始终对列表进行排序,这将适用。
关于撤回数据,有两点需要考虑:
你可以这样做:
Food* foodObj = NULL;
Clothing* clothesObj = NULL;
list<StoreItem *>::iterator it = inventory.find( /* something */ );
StoreItem* item = *it;
item->DoSomethingWithAnyStoreItem(); // It's best to only use such methods
// But if you need something only a derived class has...
foodObj = dynamic_cast<Food*>(item);
clothesObj = dynamic_cast<Clothes*>(item);
if( foodObj != NULL )
{
foodObj->DoSomethingWithFood();
Food newFood( *foodObj );
newFood.DoSomethingWithCopyOfFood();
}
else if( clothesObj != NULL )
{
clothesObj->DoSomethingWithClothes();
}
else
{
// It's neither Food, nor Clothes
}