Как вызвать метод базового класса через указатель на функцию-член?

Это связано с моей темой Указатели на функции-члены и наследование на allegro.cc Вот.

Смотрите тему на allegro.cc для примеров кода.

Я пытаюсь вызвать метод базового класса через указатель на функцию-член виртуального метода в моем WidgetBase учебный класс. Однако он вызывает виртуальный метод вместо базового класса. Я хочу вызвать метод базового класса через указатель на функцию, но в соответствии с другими потоками здесь при переполнении стека это невозможно.

Итак, мой вопрос, какие есть альтернативы? Были предложены лямбды, но я не уверен, как это реализовать, поскольку у меня мало опыта работы с C ++ 11 или C ++ 14. Идеи будут приветствоваться.

Можно вызвать метод базового класса, если вызывающий объект на самом деле является экземпляром Base Класс, но это вызывает проблемы, потому что это включает в себя создание копии объекта, для которого я хочу вызвать метод, что сводит на нет цель вызова его для объекта с самого начала.

Я надеялся, что есть какое-то волшебное приведение, которое я мог бы использовать для реализации этого, но использование статического приведения для приведения к базовому классу делает временную копию объекта, что, опять же, не то, что я хочу.

Я хочу использовать это для реализации вспомогательной функции в моем TextDecorator класс, который будет вызывать предварительно выбранную функцию установки состояния для нескольких различных объектов, содержащихся в TextDecorator, TextDecorator происходит от WidgetDecoratorBase, который является производным от WidgetBase, где находятся функции базового класса, которые я хочу вызвать. Затем эта вспомогательная функция будет вызываться в переопределенных версиях функций установщика состояний в TextDecorator учебный класс.

В основном, то, что я хочу в псевдо-C ++ коде это:

void TextDecorator::SetFlagState(bool state , void (WidgetBase::*StateSetter)(bool)) {
if (basic_text_widget) {
(basic_text_widget->WidgetBase::*StateSetter)(state);
}
(text_widget_layout->WidgetBase::->*StateSetter)(state);
(this->WidgetDecoratorBase::->*StateSetter)(state);
}

Это тогда позволило бы мне сделать мои звонки установки состояния в TextDecorator ясно и кратко, чтобы называться так:

void TextDecorator::SetEnabledState(bool state) {
SetFlagState(state , SetEnabledState);
}

где SetEnabledState это одна из функций настройки виртуального состояния в моем WidgetBase учебный класс.

Пожалуйста, держите предложения ограниченными возможными способами реализации этого. Должен быть чистый лаконичный способ сделать это в C ++.

1

Решение

Самое простое решение — это небольшой рефакторинг вашего базового класса. Вместо:

class Base {

public:

virtual void foo()
{
// The base implementation of foo().
}
};

Заменить его на:

class Base {

public:

virtual void foo()
{
foo_base();
}

void foo_base()
{
// base class implementation of foo.
}
};

Код замены на 100% логически эквивалентен. Но теперь вы можете получить указатель на foo_base() метод, и вызвать его напрямую без каких-либо особых трудностей.

1

Другие решения

Я хочу вызвать метод базового класса через указатель на функцию, но в соответствии с другими потоками здесь при переполнении стека это невозможно.

Насколько я знаю, ты не можешь этого сделать.
Указатель не несет с собой достаточно информации.
Вызов функции-члена через указатель на функцию-член похож на прямой вызов.
Я подозреваю, что не существует никакого сопоставления с такими вещами, как this->B::f() (Обратите внимание, что (this->B::*ptr)() не является допустимым синтаксисом).

Итак, мой вопрос, какие есть альтернативы? Лямбды были предложены, но я не уверен, как это осуществить

Конечно, вы можете обойти это легко с помощью лямбда-функции.
Следует минимальный рабочий пример:

#include<iostream>
#include<utility>

struct B {
virtual void f() { std::cout << "B" << std::endl; }
};

struct D: B {
void f() override { std::cout << "D" << std::endl; }

template<typename F>
void g(F &&f) { std::forward<F>(f)(*this); }
};

int main() {
D d;
d.g([](auto &i){ i.B::f(); });
}

Вместо того, чтобы передавать указатель на функцию-член, вы передаете лямбду-делегат, которая выполняет всю работу.
Недостатком этого подхода является то, что он не работает «из коробки», если функция виртуального члена является закрытой.


Как и просили в комментариях, я добавляю больше деталей.

Давайте посмотрим на это:

template<typename F>
void g(F &&f) { std::forward<F>(f)(*this); }

В этом случае, g это шаблон функции, который принимает вызываемый объект. && рядом с f потому что f является ссылкой для пересылки, и ее можно использовать для привязки либо к ссылке lvalue, либо к ссылке rvalue.
Я бы предложил прочитать этот статья Майерса, когда он также предложил условия универсальная ссылка за то же самое.
std::forward служит для пересылки переменной, сохраняя в точности ее тип. Обратите внимание, что переменная, имеющая тип Rvalue ссылка на будет ссылкой на lvalue в контексте g иначе.
В вышеупомянутой статье это объясняется более подробно.

Теперь рассмотрим эту строку кода:

d.g([](auto &i){ i.B::f(); });

Мы призываем g используя общую лямбду в качестве аргумента.
Это не является строго необходимым, мы могли бы использовать это вместо:

d.g([](D &i){ i.B::f(); });

Помимо того факта, что тип выводится, идея состоит в том, что мы получаем экземпляр класса, который наследуется от B и мы называем реализацию f от B в этом случае.
Кто требует дать такую ​​ссылку?
Вернуться к предыдущему фрагменту:

template<typename F>
void g(F &&f) { std::forward<F>(f)(*this); }

Nite, что здесь мы вызываем f (это наша лямбда) с помощью *this в качестве аргумента (он формирует ссылку на объект типа D).

Это все.

1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector