这与 allegro.cc here上的成员函数指针和继承相关。
有关代码示例,请参阅 allegro.cc 上的主题。
我正在尝试通过我的WidgetBase
类中的虚方法上的成员函数指针调用基类方法。但是它调用虚方法而不是基类1。我想通过函数指针调用基类方法,但根据堆栈溢出的其他线程,这是不可能的。
所以,我的问题是,有哪些替代方案?已经建议使用Lambdas,但我不确定如何实现它,因为我对C ++ 11或C ++ 14没什么经验。我们欢迎您的想法。
如果调用对象实际上是Base
类的实例,则可以调用基类方法但这会导致问题,因为它涉及制作我想要调用方法的对象的副本,打败了在对象上调用它的目的。
我希望有一些神奇的演员可以用来实现它,但是使用静态强制转换来强制转换为基类会产生对象的临时副本,这也不是我想要的。
我想用它来实现我的TextDecorator
类中的辅助函数,它将在TextDecorator
中包含的几个不同对象上调用预先选择的状态setter函数。 TextDecorator
派生自WidgetDecoratorBase
,它派生自WidgetBase
,这是我想要调用的基类函数所在的位置。然后将在TextDecorator
类中的状态setter函数的重写版本中调用此辅助函数。
基本上,我在伪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 ++中必须有一个简洁明了的方法。
答案 0 :(得分: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 :(得分:1)
我想通过函数指针调用基类方法,但根据堆栈溢出的其他线程,这是不可能的。
据我所知,你不能这样做
指针不带有足够的信息。
通过指向成员函数的指针调用成员函数就像直接调用一样
我怀疑与this->B::f()
之类的内容不存在任何映射(请注意(this->B::*ptr)()
不是有效的语法)。
所以,我的问题是,有哪些替代方案?已经建议使用Lambdas,但我不确定如何实现
当然,您可以使用lambda函数轻松解决问题 它遵循一个最小的工作示例:
#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(); });
}
不是将指针传递给成员函数,而是传递一个委托lambda来完成工作 这种方法的缺点是,如果虚拟成员函数是私有函数,它就无法开箱即用。
根据评论中的要求,我正在添加更多详细信息。
让我们看看这个:
template<typename F>
void g(F &&f) { std::forward<F>(f)(*this); }
在这种情况下,g
是一个接受可调用对象的函数模板。 &&
附近的f
存在,因为f
是转发引用,可用于绑定左值引用或右值引用。
我建议阅读Meyers的this文章,当时他也为同一件事提出了通用引用这两个词。
std::forward
用于通过保留其类型来转发变量。请注意,具有 rvalue引用的变量在g
的上下文中将是左值引用。
在上面提到的文章中,将对此进行更详细的解释。
现在考虑这行代码:
d.g([](auto &i){ i.B::f(); });
我们使用通用lambda作为参数调用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
(即我们的lambda)(它形成对D
类型的对象的引用。)
就是这样。