Дочерний класс 'Dynami c метод вызывает виртуальный метод родительского класса при использовании в лямбда-захвате / приводит к ошибке сегментации - PullRequest
2 голосов
/ 08 мая 2020

Edit: с ключевым словом final в реализациях виртуальной функции приводит к печати правильной строки, но зачем здесь ключевое слово final? Может кто-нибудь объяснить?

Я возился с различными c шаблонами, у меня довольно общие c классы D1, D2, D3, ... и все они происходят от класса A. Каждый класс имеет stati c и функции печати Dynami c, родительский класс имеет виртуальную функцию c print для Dynami c диспетчеризации. Когда я пытаюсь воспроизвести его в одном файле:

class A { 
  public:
  virtual void printDynamic();
  static void printStatic();
}

class D1 : public A {
  public:
  virtual void printDynamic();
  static void printStatic();
}

И у меня есть следующие варианты:

std::variant<A,As...> apvar;
std::variant<A*,As*...> avar;

Я создаю оба варианта со всеми производными классами D1, D2, .. . (Я знаю повышающие указатели, я просто хочу разыменовать их типы и делать случайные вещи)

Я реализовал рекурсивные посетители для оберток, мне нужно это зафиксировать, потому что я инкапсулировал большинство функций в классе, когда я вызываю посетителя на занятия, я получаю имена «DX», «DX»; X соответствует 1.

    template<class X, class Y, class... Zs>
    void visit_actor(){
        std::visit(
            [this](auto&& value){
                if constexpr(std::is_same<expr_type<decltype(value)>,expr_type<X>>::value){
                    value.printStaticName();
                    value.printDynamicName();
                } else{
                    visit_actor<Y,Zs...>();
                }
            }, avar
        );
    }

Но если я вызываю посетителя по вариантам указателя и когда я вызываю функции: Для функции stati c я получаю: «DX» с X, соответствующим I, но когда я вызываю функцию Dynami c, я получаю имя: «Abstract A».

    template<class X, class Y, class... Zs>
    void visit_pointer(){
        std::visit(
            [this](auto&& value){
                if constexpr(std::is_same<expr_type<decltype(value)>,expr_type<X>>::value){
                    value->printStaticName();
                    value->printDynamicName();
                } else{
                    visit_pointer<Y,Zs...>();
                }
            }, apvar
        );
    }

Я пробовал прочитать об этом в документации по C ++, но пока не смог найти причину. В чем может быть причина того, что функция stati c производного класса вызывается, но вызывается виртуальная функция родителей?

Для примера Minimal Producable вам необходимо создать экземпляры классов: *

Результат:

thrud@thrud ~/wörk/test $ g++ main.cpp -std=c++17
thrud@thrud ~/wörk/test $ ./a.out 

dynamic D2
y
z
static D2
dynamic D2
d
a
static D2
Segmentation fault

Итак, я думаю, что наткнулся на неопределенное поведение, но все же хотел бы знать причину.

1 Ответ

2 голосов
/ 09 мая 2020

TemplatedAGraph(X a) : ap(&a), aw(a) {} сохраняет указатель на локальную переменную в ap. Вскоре после этого указатель становится висящим. Любая попытка получить к нему доступ затем демонстрирует неопределенное поведение.

Вы могли иметь в виду TemplatedAGraph(X& a) :.... Таким образом, ваш код работает , насколько я могу судить.

...