我正在制作一个篮子' (容器)存放物品' (类)派生自另一个类。
我们的想法是方法select
返回正确的类(派生),而不是基础。
#include <iostream>
#include <map>
#include <typeinfo>
class Item;
class Pencil;
class Basket
{
public:
Basket();
void insert(int id, Item item);
Item select(int id);
private:
std::map<int, Item> basket;
};
class Item
{
};
class Pencil : public Item
{
public:
Pencil() {}
void draw() { std::cout << "stackoverflow" << std::endl; }
};
Basket::Basket() {}
void Basket::insert(int id, Item item)
{
basket.insert(std::pair<int, Item>(id, item));
}
Item Basket::select(int id)
{
return basket[id];
}
int main(int argc, char ** argv)
{
Basket basket;
Pencil pencil;
basket.insert(1, pencil);
auto redpen = basket.select(1);
std::cout << typeid(redpen).name() << std::endl;
return 0;
}
输出:4Item(期望为6Pencil)
这样我就无法使用方法draw
,因为这不是我在篮子(容器)上添加的项目(类),而是转换为基础类。
有没有办法返回正确的类,我的意思是,派生的类,但保持这种结构?
谢谢。
答案 0 :(得分:1)
你不能按值返回一个派生类,因为那样你就会得到切片,这就意味着复制派生就好像它只是一个基础,留下所有后面的东西(包括它应该是派生的任何提示)。 / p>
相反,返回指向新分配的派生的指针作为基*。不要忘记清理它。
为了捕获删除失败,您可能会查看智能指针,也可以查看共享缓存的返回值
无论如何,当返回的值实际存在时,您也可以返回const& base
。
答案 1 :(得分:1)
您希望将C ++多态性与RTTI(运行时类型标识)一起使用。一种解决方案是使用指针,因此具有:
class Basket
{
public:
Basket();
void insert(int id, Item *item);
Item *select(int id);
private:
std::map<int, Item*> basket;
};
这需要一些动态分配(新操作),你可以通过使用内存头的std :: shared_ptr和C ++ 11来摆脱删除操作。
答案 2 :(得分:1)
您在对问题的评论中请求的示例:
#include <iostream>
#include <map>
#include <memory>
#include <typeinfo>
class Item;
class Pencil;
class Basket
{
public:
Basket();
void insert( int id, std::shared_ptr<Item> item );
auto select( int id ) -> std::shared_ptr<Item>;
private:
std::map< int, std::shared_ptr<Item> > basket;
};
class Item
{
public:
virtual ~Item() {}
};
class Pencil
: public Item
{
public:
Pencil() {}
void draw() { std::cout << "stackoverflow" << std::endl; }
};
Basket::Basket() {}
void Basket::insert( int const id, std::shared_ptr<Item> const item )
{ basket[id] = item; }
auto Basket::select( int const id )
-> std::shared_ptr<Item>
{ return basket[id]; }
int main()
{
Basket basket;
basket.insert(1, std::make_shared<Pencil>() );
auto redpen = basket.select( 1 );
std::cout << typeid(*redpen).name() << std::endl;
}