为什么从基类而不是子类调用虚拟成员函数

时间:2019-06-24 15:16:12

标签: c++ templates coliru

我正在编写一小段代码,以弄清楚如何将不同的模板专长存储到一个数据结构中(例如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;
}

运行上面的代码段时,使用在线编译器colirug++ -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 个答案:

答案 0 :(得分:1)

std::vector<Element> elements;

这意味着elementsvector类句点实例的Element。例如,vector分配内存时,它为每个实例分配连续的空间,而sizeof(Element)则保留。

如何使用它来保存SparseSet的实例?

您可能要使用std::vector<std::unique_ptr<Element>>,因为unique_ptr<Element>可以容纳指向SparseSet的指针。