如何将被覆盖的虚函数的指针发送到基class?
How to send a pointer of an overriden virtual function to the base class?
一个例子:
class Base
{
protected:
virtual void function() { std::cout << "Base\n"; }
void callfunction(void (Base::* func)()) { (this->*func)(); }
};
class Derived1 : public Base
{
public:
void publicCall() { callfunction(&Derived1::function); }
private:
void function() override { std::cout << "Derived1\n"; }
};
我希望能够将派生函数指针发送到基 class 以实现可在基 class 中指定的模式。因此,重用代码。
但是,我不确定基 class 中的类型应该是什么,因为 Base::* 不是 Derived1::*.
我收到以下错误:
No instance of overloaded function callfunction matches the argument list: arguments types are (Derived1::*)
现在显然,我可以将数据类型更改为 Derived1::*
,但这不允许我将其他派生的 class 虚拟函数发送回 Base
来处理, 例如 Derived2::function()
可以像这样创建一个模板类的函数吗?
使用 std::function<>
而不是 C
样式函数指针。
std::function<returnType (parameterType)> functionPointer = functionName;
不要忘记包括 <functional>
。
我认为这会解决您的问题,但肯定是首选。
直接传递:
void callfunciton(const std::function<void()>& func);
并由
致电
callfunction([]{ function(); });
编辑:
阅读 this 了解为什么应该使用 std::function<>
。
我认为模板函数应该可以工作
template<class _DType>
void Base::callFunction(void(_DType::*func)()) { func(); }
然后是 Derived1
中的函数
void Derived1::publicCall() { Base::callFunction(&Derived1::function); }
这项工作只要 Derived1
是由 Base
派生的,那不是你写的,但我假设你只是错过了,反正下次我会添加 class Derived1: public Base
有一个更清晰的代码。
您的问题是询问 CRTP,它是 Jim Coplien 在 1995 年发表的一篇题为“奇怪的重复模板模式”的文章中描述的成语的一个命名不佳但众所周知的标签。这个想法有很好的文档记录,所以我不会深入,但这个想法非常简单:基础 class 采用模板参数,派生 class 将其类型提供给基础。然后基础 class 可以将 this 指针“向下转换”到派生类型并调用函数而不需要虚拟调用。
https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
What is the curiously recurring template pattern (CRTP)?
您可以将成员函数指针转换为基本 class 成员函数指针类型:callfunction(static_cast<void (Base::*)()>(&Derived1::function));
。完整示例:
class Base
{
protected:
virtual void function() { std::cout << "Base\n"; }
void callfunction(void (Base::* func)()) { (this->*func)(); }
};
class Derived1 : public Base
{
public:
void publicCall() { callfunction(static_cast<void (Base::*)()>(&Derived1::function)); }
private:
void function() override { std::cout << "Derived1\n"; }
};
这是允许的;见 cppreference on pointers to member functions:
Pointer to member function of a base class can be implicitly converted to pointer to the same member function of a derived class ...
Conversion in the opposite direction, from a pointer to member function of a derived class to a pointer to member function of an unambiguous non-virtual base class, is allowed with static_cast
and explicit cast
在这种情况下,我们将派生转换为基而不是相反,因此我们需要 static_cast
。
您可以通过从模板中强制转换 Base
来避免从调用站点强制转换:
class Base
{
protected:
virtual void function() { std::cout << "Base\n"; }
void callfunction(void (Base::* func)()) { (this->*func)(); }
template <typename Derived, std::enable_if_t<std::is_convertible_v<Derived const*, Base const*>, int> = 0>
void callfunction(void (Derived::* func)()) { callfunction(static_cast<void (Base::*)()>(func)); }
};
class Derived1 : public Base
{
public:
void publicCall() { callfunction(&Derived1::function); }
private:
void function() override { std::cout << "Derived1\n"; }
};
编译器资源管理器link:https://godbolt.org/z/3x8qPK4Tf
只需发送&Base::function
。既然是虚拟的,就叫对的吧。
这里唯一的问题是 Base::function
受到保护,您无法从 Derived
访问它(奇怪但真实)。 OTOH &Derived::function
不会转换为 void (Base::* func)()
(并且有充分的理由)。所以你必须要么制作 Base::function
public,要么提供一个访问器:
class Base {
...
protected:
auto getFunction() { return &Base::function; }
一个例子:
class Base
{
protected:
virtual void function() { std::cout << "Base\n"; }
void callfunction(void (Base::* func)()) { (this->*func)(); }
};
class Derived1 : public Base
{
public:
void publicCall() { callfunction(&Derived1::function); }
private:
void function() override { std::cout << "Derived1\n"; }
};
我希望能够将派生函数指针发送到基 class 以实现可在基 class 中指定的模式。因此,重用代码。
但是,我不确定基 class 中的类型应该是什么,因为 Base::* 不是 Derived1::*.
我收到以下错误:
No instance of overloaded function callfunction matches the argument list: arguments types are (Derived1::*)
现在显然,我可以将数据类型更改为 Derived1::*
,但这不允许我将其他派生的 class 虚拟函数发送回 Base
来处理, 例如 Derived2::function()
可以像这样创建一个模板类的函数吗?
使用 std::function<>
而不是 C
样式函数指针。
std::function<returnType (parameterType)> functionPointer = functionName;
不要忘记包括 <functional>
。
我认为这会解决您的问题,但肯定是首选。
直接传递:
void callfunciton(const std::function<void()>& func);
并由
致电callfunction([]{ function(); });
编辑:
阅读 this 了解为什么应该使用 std::function<>
。
我认为模板函数应该可以工作
template<class _DType>
void Base::callFunction(void(_DType::*func)()) { func(); }
然后是 Derived1
void Derived1::publicCall() { Base::callFunction(&Derived1::function); }
这项工作只要 Derived1
是由 Base
派生的,那不是你写的,但我假设你只是错过了,反正下次我会添加 class Derived1: public Base
有一个更清晰的代码。
您的问题是询问 CRTP,它是 Jim Coplien 在 1995 年发表的一篇题为“奇怪的重复模板模式”的文章中描述的成语的一个命名不佳但众所周知的标签。这个想法有很好的文档记录,所以我不会深入,但这个想法非常简单:基础 class 采用模板参数,派生 class 将其类型提供给基础。然后基础 class 可以将 this 指针“向下转换”到派生类型并调用函数而不需要虚拟调用。
https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
What is the curiously recurring template pattern (CRTP)?
您可以将成员函数指针转换为基本 class 成员函数指针类型:callfunction(static_cast<void (Base::*)()>(&Derived1::function));
。完整示例:
class Base
{
protected:
virtual void function() { std::cout << "Base\n"; }
void callfunction(void (Base::* func)()) { (this->*func)(); }
};
class Derived1 : public Base
{
public:
void publicCall() { callfunction(static_cast<void (Base::*)()>(&Derived1::function)); }
private:
void function() override { std::cout << "Derived1\n"; }
};
这是允许的;见 cppreference on pointers to member functions:
Pointer to member function of a base class can be implicitly converted to pointer to the same member function of a derived class ...
Conversion in the opposite direction, from a pointer to member function of a derived class to a pointer to member function of an unambiguous non-virtual base class, is allowed withstatic_cast
and explicit cast
在这种情况下,我们将派生转换为基而不是相反,因此我们需要 static_cast
。
您可以通过从模板中强制转换 Base
来避免从调用站点强制转换:
class Base
{
protected:
virtual void function() { std::cout << "Base\n"; }
void callfunction(void (Base::* func)()) { (this->*func)(); }
template <typename Derived, std::enable_if_t<std::is_convertible_v<Derived const*, Base const*>, int> = 0>
void callfunction(void (Derived::* func)()) { callfunction(static_cast<void (Base::*)()>(func)); }
};
class Derived1 : public Base
{
public:
void publicCall() { callfunction(&Derived1::function); }
private:
void function() override { std::cout << "Derived1\n"; }
};
编译器资源管理器link:https://godbolt.org/z/3x8qPK4Tf
只需发送&Base::function
。既然是虚拟的,就叫对的吧。
这里唯一的问题是 Base::function
受到保护,您无法从 Derived
访问它(奇怪但真实)。 OTOH &Derived::function
不会转换为 void (Base::* func)()
(并且有充分的理由)。所以你必须要么制作 Base::function
public,要么提供一个访问器:
class Base {
...
protected:
auto getFunction() { return &Base::function; }