Почему виртуальная функция-член вызывается из базового класса, а не из подкласса
Я писал короткий фрагмент кода, чтобы выяснить, как я буду хранить различные специализации шаблона в одной структуре данных (например, vector
). Я в курсе tuple
но это не хорошо, потому что я хочу иметь возможность добавлять специализации после tuple
был построен.
Ниже приведен фрагмент кода, который я придумал. Короче говоря, моя идея состояла в том, чтобы каждая специализация шаблона наследовалась от общего class Element
а затем сохранить такие экземпляры в vector<Element>
, Это сработало, но теперь, когда я получаю доступ к этим данным из vector
Я получаю к нему доступ как Element
, Мне нужен какой-то способ узнать, какой Element
в паре с какой специализацией шаблона.
С помощью typeid
непосредственно на элементы из vector
возвращает базовый тип Я пытался обойти это, имея функцию-член runtime_type
вернуть эту информацию из подкласса. К сожалению, это не работает, потому что функция-член из SparseSet<T>
не переопределяет виртуальную функцию-член из базового класса. Я не уверен почему.
#include <vector>
#include <iostream>
#include <tuple>
#include <typeinfo>
#include <algorithm>
class Element
{
public:
virtual const std::type_info& runtime_type()
{
std::cout << " Called base ";
return typeid(*this);
}
virtual ~Element() = default;
};
template<class T>
class SparseSet : public Element
{
public:
T param;
const std::type_info& runtime_type() override
{
std::cout << " Called derived ";
return typeid(*this);
}
};
class Manager
{
public:
std::vector<Element> elements;
template<class T>
bool has()
{
const auto it = std::find_if(elements.begin(), elements.end(), [](auto &element) {
std::cout << "typeid(element) = " << element.runtime_type().name() << std::endl;
std::cout << "typeid(T) = " << typeid(T).name() << std::endl;
return typeid(element) == typeid(T);
});
return it != elements.end();
}
};
int main()
{
SparseSet<int> ss_int;
ss_int.param = 3;
SparseSet<char> ss_char;
ss_char.param = 'a';
Manager manager;
manager.elements.push_back(ss_int);
manager.elements.push_back(ss_char);
std::cout << manager.has<SparseSet<int>>() << std::endl;
return 0;
}
Когда я запускаю фрагмент выше, используя онлайн-компилятор coliru (g++ -std=c++17 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
), Я получаю следующий вывод.
typeid(element) = Called base 7Element
typeid(T) = 9SparseSetIiE
typeid(element) = Called base 7Element
typeid(T) = 9SparseSetIiE
0
1 ответ
std::vector<Element> elements;
Это значит, что elements
это vector
экземпляров класса Element
, период. Когда vector
выделяет память, например, выделяет непрерывное пространство, оставляя sizeof(Element)
для каждого экземпляра. Как это можно использовать для хранения экземпляра SparseSet
?
Вы можете использовать std::vector<std::unique_ptr<Element>>
, так как unique_ptr<Element>
может содержать указатель на SparseSet
,