Хеш-таблица иерархии классов - PullRequest
0 голосов
/ 14 января 2019

У меня следующая ситуация:

class A {
public:
 int a;

 // Just for RTTI
 virtual ~A() = default;
}

class B : public A {
public:
 int b;
}

И затем я создаю std::unordered_map<int, A>, где я хочу иметь возможность хранить как A s, так и B s, и вернуться к их исходному представлению.

Я всегда знаю, соответствует ли элемент A или B из контекста в точке find(), просто взглянув на ключ.

Однако, если я запускаю следующую программу:

#include <unordered_map>
#include <iostream>

using namespace std;


class A {
public:
 int a{};

 A() = default;
 A(int a) : a(a){}

 // Just for RTTI
 virtual ~A() = default;
};

class B : public A {
public:
 B(int a, int b) : A(a), b(b) {}
 int b;
};


int main()
{
    std::unordered_map<int, A> m;
    m[1] = A(4);
    m[2] = B(2,5);

    if (dynamic_cast<B *>(&m.at(2)) == nullptr) {
        std::cout << "FAIL!" << std::endl;
    }
}

Я получаю «FAIL» на моем экране. Я не ожидал такого поведения; как я могу заставить это работать?

Ответы [ 2 ]

0 голосов
/ 14 января 2019

На всякий случай, если кто-нибудь столкнется с этим в будущем, другой путь, по которому вы можете пойти, - это использовать std::variant и сохранить единственную хеш-таблицу без, по крайней мере, непосредственного использования указателей, как предложил Джереми.

0 голосов
/ 14 января 2019

То, с чем вы столкнулись, это нарезка объектов - в частности, ваш unordered_set<int, A> может содержать только объекты типа A. Когда вы пытаетесь поместить в него объект типа B, он компилируется, но только часть суперкласса объекта B фактически копируется в структуру данных - часть подкласса (то есть часть * 1006). * объект, который не является частью суперкласса A) "обрезается" и отбрасывается, а то, что хранится в наборе, является просто еще одним A.

Если вы хотите, чтобы ваш unordered_set содержал значения различных подклассов, тогда единственный способ сделать это - сохранить объекты-значения косвенно через некоторый указатель; например, вместо этого вы можете использовать unordered_set<int, A*> или, что еще лучше, unordered_set<int, shared_ptr<A> > (так что вы будете защищены от утечек памяти). Затем вам нужно выделить каждый объект A / B в куче, прежде чем вставлять его в набор.

(Альтернативным подходом было бы сохранить отдельные unordered_set для каждого подкласса, например, иметь unordered_set<int, A> и a unordered_set<int, B>. Конечно, недостатком является усложнение вашего кода вызова ) * * тысяча двадцать-один

...