返回派生而不是基类

时间:2014-04-20 17:17:41

标签: c++

我正在制作一个篮子' (容器)存放物品' (类)派生自另一个类。 我们的想法是方法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;
}

Live preview

  

输出:4Item(期望为6Pencil)

这样我就无法使用方法draw,因为这不是我在篮子(容器)上添加的项目(类),而是转换为基础类。

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

谢谢。

3 个答案:

答案 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;
}