返回派生类,而不是基类

Returning the derived instead of the base class

本文关键字:基类 派生 返回      更新时间:2023-10-16

我正在创建一个"basket"(容器)来存储从另一个类派生的"items"(类)。其思想是方法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;
}

实时预览

输出:4项(预计为6项)

通过这种方式,我不能使用方法draw,因为这不是我添加到篮(容器)上的项(类),它已转换为基类。

有没有一种方法可以返回正确的类,我的意思是,派生的类,但保持这种结构?

谢谢。

您在问题评论中请求的示例:

#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;
}

不能按值返回派生类,因为这样会得到切片,这意味着复制派生类,就好像它只是一个基一样,留下所有添加的内容(包括任何应该是派生类的提示)。

相反,返回一个指向新分配的派生的指针作为基*。不过别忘了清理一下
为了捕捉删除失败,您可以查看智能指针,也可以共享缓存的返回值
当返回的值实际存在的时间与需要的时间一样长时,您也可以返回const& base

您希望将C++多态性与RTTI(运行时类型标识)一起使用。一种解决方案是使用指针,因此具有:

class Basket
{
public:
    Basket();
    void insert(int id, Item *item);
    Item *select(int id);
private:
    std::map<int, Item*> basket;
};

这将需要一些动态分配(新操作),并且您可以使用C++11通过使用内存头的std::shared_ptr来消除删除操作。