以下代码无法编译:
struct Base
{
std::vector<void(Base::*)(void)> x;
};
struct Derived : public Base
{
void foo() {}
};
// ...
Derived d;
d.x.push_back(&Derived::foo);
是否可以引用模板成员x
中的派生类?在上面的示例中,我恰好指定了Base
,派生类无法将其自身的成员函数推入向量x
中。
答案 0 :(得分:0)
可以,但是没有隐式转换;它需要强制转换。
Derived d;
d.x.push_back(static_cast<void(Base::*)()>(&Derived::foo));
警告是,如果您使用指向对象的指针实际上不是Derived
,则该行为是不确定的。小心踩。
作为附录,如果要在获取指针时摆脱强制类型转换,可以通过封装push(通过一些静态类型检查来引导)来做到这一点:
struct Base
{
std::vector<void(Base::*)(void)> x;
template<class D>
auto push_member(void (D::* p)()) ->
std::enable_if_t<std::is_base_of<Base, D>::value> {
x.push_back(static_cast<void(Base::*)()>(p));
}
};
答案 1 :(得分:0)
铸造是不好的,因为您的代码必须假定将仅对Derived
类的实例调用此方法。这意味着您要么必须假设x
中的所有项目都是Derived
的实例(在这种情况下,x
的声明是通用的,应更改为std::vector<void(Derived::*)(void)> x;
)否则,您必须保留额外的信息,即哪种类方法存储在x
的特定位置。两种方法都不好。
在现代C ++中,最好这样做:
struct Base
{
std::vector<std::function<void()>> x;
};
struct Derived : public Base
{
void foo() {}
};
// ...
Derived d;
d.x.push_back([&d](){ d.foo(); });
另一种好的方法是CRTP:
template<class T>
struct Base
{
std::vector<void(T::*)(void)> x;
};
struct Derived : public Base<Derived>
{
void foo() {}
};
// ...
Derived d;
d.x.push_back(&Derived::foo);
答案 2 :(得分:0)
我想我会通过在基础上通过非虚拟成员函数进行调用来表达这一点。
示例:
#include <vector>
struct Base
{
std::vector<void(Base::*)(void)> x;
// public non-virtual interface
void perform_foo()
{
foo();
}
private:
// private virtual interface for the implementation
virtual void foo() = 0;
};
struct Derived : public Base
{
private:
// override private virtual interface
void foo() override {}
};
// ...
int main()
{
Derived d;
d.x.push_back(&Base::perform_foo);
auto call_them = [](Base& b)
{
for (auto&& item : b.x)
{
(b.*item)();
}
};
call_them(d);
}