将派生类作为值放入STL映射中

Putting derived classes into STL maps as values

本文关键字:STL 映射 派生      更新时间:2023-10-16

我有两个简单的类。基类A和派生类B。出于调试目的,复制构造函数和析构函数被重写为cout内容:

class A
{
protected:
    char * c;
public:
    A(char * c) : c(c) { cout << "+A " << this << "n"; }
    A(const A& other) : c(other.c) { cout << "*A " << this << "n"; }
    ~A() { cout << "-A " << this << "n"; }
};
class B : public A
{
public:
    B(char * c) : A(c) { cout << "+B " << this << "n"; }
    B(const B& other) : A(other.c) { cout << "*B " << this << "n"; }
    ~B() { cout << "-B " << this << "n"; }
};

以下是我如何将insert的一个实例B map:

    {
        cout << "-- 1n";
        map<string, A> m;
        cout << "-- 2n";
        m.insert(pair<string, A>( "b", B("bVal")));
        cout << "-- 3n";
    }
    cout << "-- 4 --n";

结果:

-- 1
-- 2
+A 0051F620
+B 0051F620
*A 0051F5EC
*A 00BD8BAC
-A 0051F5EC
-B 0051F620
-A 0051F620
-- 3
-A 00BD8BAC
-- 4 --

关于实例的创建,我阅读如下:

  1. B由我自己的代码创建
  2. CCD_ 8被CCD_
  3. 最后一个A实例然后被插入的map再次复制

顺便说一句,将insert行中的pair更改为pair<string, B>并没有起到什么作用,它只是将第二步更改为创建B而不是A,但最后一步会将其再次降级为A。在映射本身符合销毁条件之前,映射中唯一保留的实例似乎是最后一个A实例。

我做错了什么?我应该如何将派生类放入映射中?使用格式的地图

map<string, A*>

也许吧?

更新-解决方案由于我的解决方案没有直接在接受的答案中说明,而是以建议的形式隐藏在其评论中,因此我最终要做的是:

map<string, shared_ptr<A>> m;

这假设您的构建环境支持shared_ptr,而我的(C++/CLI,Visual Studio 2010)支持CCD_ 20。

这被称为切片,当派生类不适合它所分配的对象时就会发生这种情况

B b;
A a = b; // This would only copy the A part of B.

如果要在地图中存储不同类型的对象,请使用map<。。。,正如你正确推断的那样,A**是前进的道路。由于对象不是存储在映射中,而是存储在堆中的某个位置,因此不需要复制它,而且它总是适合的。

 map<string, A> m;

切片插入的对象,该对象将成为A,丢失所有其他信息(不再是B)。

你的直觉是正确的,你需要使用指针,或者更好的是,使用智能指针。

此外,A中的析构函数需要是virtual:

class A
{
    //...
    virtual ~A() { cout << "-A " << this << "n"; }
};

否则通过指向CCD_ 26的指针删除实际类型为CCD_。