【发布时间】:2020-11-19 14:20:36
【问题描述】:
我对 C++ 比较陌生,我正在从事一个个人项目,以练习我需要创建一个可以采用具有不同签名的函数指针的类。
这个想法是类的每个实例都将存储一个指向特定函数的指针,并且可以随时调用该函数。
为了更好地了解我想要什么,让我更详细地解释一下我想要做什么。我正在做的项目是一个非常基本的控制台游戏,我正在尝试创建的对象是一个对象,它将存储玩家在游戏中可以访问的每个位置的详细信息。
(免责声明:我知道我稍后描述的大部分内容对于基本的主机游戏来说可能是多余的。我可以使用简单的函数轻松地将整个游戏制作成几个文件,而且我知道该怎么做那个。但是这里的想法是我想练习更高级的 C++ 技术,而不必弄清楚一个复杂的项目。所以,既然我知道如何制作一个基本的控制台游戏,我认为尝试和计算是个好主意了解如何使用更先进的技术实现相同的结果)
我认为应该存储的细节之一是每个位置发生的事情,基本上是输出到屏幕的文本,描述发生的事情并提示用户采取行动。
由于每个位置都不同,我不能只在类中声明和实现一个函数。
解决此问题的一种方法是创建一个具有虚函数的基类,然后在一系列派生类中实现该函数,每个派生类都定义一个新位置。
这种方法的问题是它使每个位置成为一个可以进一步继承和实例化的类,我不需要,因为每个位置只有一个实例。
我当然可以只创建该类的 1 个实例,但我想看看是否有办法避免为每个位置创建单独的类。
这就是我开始考虑函数指针的原因。
现在,我知道我可以声明一个函数指针并在这样的类中初始化它:
class Test
{
public:
Test(void (*p)())
: print{p}
{}
private:
void (*print)();
};
只要函数返回 void 并且不接受任何参数,它就可以正常工作。
所以,我想也许我可以用模板做到这一点:
template <typename Function>
class Test
{
public:
Test(Function *p)
: print{p}
{}
Function *print;
};
这实际上效果很好。我现在可以拥有一个接受具有不同返回类型的不同函数的类。
我可以通过以下方式创建类的实例:
void print();
Test<void ()> a {print};
但是,我对这种方法有一个问题。因为它是一个类模板,所以无论传递给它们的函数如何,我都不能有一个指针来指向 Test 类的实例。
例如,如果我声明以下指针:
Test<void ()> *b = &a;
除非传递给它的函数指针也返回 void 并且不接受任何参数,否则无法将该指针重新分配给 Test 类的另一个实例。否则,我必须创建一个新指针。
有没有办法避免这种情况?有没有比使用函数指针更好的方法来实现我正在寻找的东西?
非常感谢您,很抱歉给您这么长的信息。
【问题讨论】:
-
为什么不同位置的类型会不同?
-
@user253751:因为虚函数需要不同。逻辑是有道理的;虚函数的典型实现将函数指针存储在表中。这是一个很小的开销,但这里不需要。然而,我认为开销仍然值得,因为它允许您使用教科书中的标准 C++。
-
假设您无论如何都想通过一个指针调用您的函数,我相信您必须使所有函数都具有相同的返回类型。它们还必须具有相同的调用签名,但您可以尽早将其他参数绑定到您的函数。一个工具是std::function,它可以绑定普通函数以及带有成员函数的对象和lambdas。后者提供了另一个工具来制作适配器(用于绑定额外的参数)。
-
当然,lambda 也可以适应返回类型不匹配的函数。但是,如果您自己编写这些函数,如果实际用例(通过唯一函数指针调用)对此没有任何用途,我不明白为什么您必须具有不同的返回类型。
-
很可能,函数不会有不同的返回类型。但由于我在练习,我试图想象一个他们可能会遇到的场景,并试图找到解决它的方法。