c ++: допустимо ли множественное наследование от класса шаблона и общего класса? - PullRequest
0 голосов
/ 04 мая 2020

Я пытаюсь выяснить, почему b-> boo () на самом деле вызывает a.far (). множественное наследование от класса шаблона и общего класса запрещено? почему порядок наследования имеет значение? Код здесь:

#include <iostream>

template <int somecount>
class inner_parent_class
{
public:
    int array[somecount];
    virtual void far() = 0;
};

class any_class
{
public:
    virtual void boo() = 0;
};

template <int somecount>
class child_class_bad : public inner_parent_class<somecount>, public any_class
{
public:
    virtual void boo() override
    {
        std::cout << "call me" << std::endl;
    }

    virtual void far() override
    {
        std::cout << "do not call me" << std::endl;
    }
};

template <int somecount>
class child_class_good : public any_class, public inner_parent_class<somecount>
{
public:
    virtual void boo() override
    {
        std::cout << "call me" << std::endl;
    }

    virtual void far() override
    {
        std::cout << "do not call me" << std::endl;
    }
};

int main()
{
    {
        child_class_good<32> a;
        any_class* b;
        auto c = dynamic_cast<void*>(&a);
        b = reinterpret_cast<any_class*>(c);
        b->boo();
    }
    {
        child_class_bad<32> a;
        any_class* b;
        auto c = dynamic_cast<void*>(&a);
        b = reinterpret_cast<any_class*>(c);
        b->boo();
    }

    return 0;
}

@ G CC 9.3.0

@ VS 2019 16.5.3

Я полагаю, что оба дочерних класса (child_class_good и child_class_bad) являются разными классами, даже если их имена классов совпадают, поскольку они являются шаблонными классами и создаются отдельно во время компиляции. Тем не менее, у каждого класса может быть своя собственная v-таблица, поэтому я думаю, что вызов boo () в качестве общего родительского класса any_class должен корректно работать.

1 Ответ

3 голосов
/ 04 мая 2020

reinterpret_cast нельзя использовать, чтобы делать то, что вы пытаетесь сделать. reinterpret_cast из void* в T* создает указатель на действительный T*, только если указанный void* указатель был указателем на объект типа T.

Выполнение dynamic_cast<void*>(p) возвращает void*, которое указывает на наиболее производный объект, на который указывает p. Поскольку ваш &a на самом деле является самым производным объектом, на который он указывает, он просто преобразует указатель в void*.

Затем вы выполняете reinterpret_cast<any_class*> для этого void*. void* указывает на объект типа child_class_good<32> или child_class_bad<32>. Ваш актер говорит, что указатель на самом деле указывает на any_class. Это неверно (ни один тип не является стандартным макетом, поэтому макет базовых классов не определен), и поэтому попытка использовать результаты приведет к неопределенному поведению.

Случай, который вы идентифицируете как good, так же недействительно, как bad; просто случается с работой.

Неясно, почему вы пытаетесь делать то, что вы пытаетесь сделать, но нет действительного способа взять void* указание на наиболее производный объект неизвестного типа и приведение его к чему-либо полезному. Чтобы использовать void*, вы должны знать точный тип, который использовался для производства этого void*.

...