【问题标题】:Refactoring C++, "no matching function to call"重构 C++,“没有要调用的匹配函数”
【发布时间】:2019-12-30 11:48:42
【问题描述】:

我正在学习如何有效地为 ESP8266 项目分离我的 C++ 代码,并且在提取网络服务器函数和对象时遇到了一些问题。我使用 this 教程中的示例代码作为我的基点。

我觉得我了解了如何构建类和标头的基础知识,但是当我尝试在我的类中使用另一个类时,我遇到了错误……但仅限于某些函数。

这是我的 main.cpp:

#include <CServer.h>

CServer clientServer(80); //create a CServer, which will create a private WebServer object on init.

void setup(void)
{     
  clientServer.startRoutes(); //start routes declared in CServer.cpp
  clientServer.begin(); // start the server
} 

void loop(void){
  clientServer.handleClient();                    // Listen for HTTP requests from clients
}

这是我的 CServer.h:

//begin include for class CServer to handle client server functions
#ifndef CSERVER_H
#define CSERVER_H

#include <ESP8266WebServer.h>
//Client server functions are handled by this class.
ESP8266WebServer
class CServer
{
private:
  ESP8266WebServer server; //local instance of the webserver object
public:
  CServer(int port);

  void handleClient();
  void handleNotFound();
  void handleRoot();
  void begin();
  void startRoutes();
};

#endif

最后是 CServer.cpp

#include "CServer.h"

CServer::CServer(int port)
{
  ESP8266WebServer server(port); //create a server with the passed port
}

void CServer::handleClient()
{
  server.handleClient();
};

void CServer::handleRoot()
{
  server.send(200, "text/plain", "Hello world!"); // Send HTTP status 200 (Ok) and send some text to the browser/client
}

void CServer::handleNotFound()
{
  server.send(404, "text/plain", "404: Not found"); // Send HTTP status 404 (Not Found) when there's no handler for the URI in the request
}

void CServer::begin()
{
  server.begin();
}

void CServer::startRoutes()
{
  server.on("/", handleRoot);
  server.onNotFound(handleNotFound);
}

我收到了错误:

没有匹配的调用函数 'esp8266webserver::ESP8266WebServerTemplate::on(const char [2],)'

对于 handleRoot 和 handleNotFound 函数,我试图在 .cpp 文件的最后传递给“server.on”和“server.onNotFound”。

我希望使用许多不同的库等来构建设备,并且非常想知道如何使用这种策略有效地清理我的代码,因此了解正确的方法至关重要。

【问题讨论】:

  • 与您的问题无关,但CServer 的构造函数在主体中创建了一个名为server 的变量,这意味着它不会初始化名为server 的类成员。这两件事被命名为server这一事实并不会神奇地导致它们相关。

标签: c++ arduino refactoring esp8266


【解决方案1】:

您正在尝试将非静态成员函数传递给 server.on("/", handleRoot);,该函数需要签名 void() 的可调用函数(即可以在没有任何参数的情况下调用并返回 void 的可调用函数。

然而,非静态成员函数不是没有任何参数的可调用函数。它至少需要一个参数,即指向类实例的隐式 this 指针。

如果您希望处理程序在调用 startRoutes 的当前类实例上调用 handleRoot,则使用 lambda 调用成员并捕获 this

server.on("/", [this]{ handleRoot(); });

正如@Peter 在问题 cmets 中提到的,您也没有正确初始化 server 成员。相反,您正在创建ESP8266WebServer 的本地实例,也称为server,但它是构造函数的本地实例,并在构造函数离开时被销毁。该实例与类成员实例无关,只是它们共享类型和名称。

如果你想用port作为参数来初始化server成员,你可以在构造函数的成员初始化列表中这样做:

CServer::CServer(int port) : server(port)
{
}

【讨论】:

  • 这成功了!一切实际上都按预期运行。不过我很好奇@peter 的评论。我试图做的是在实例化 CServer 类时,我想创建一个 ESP8266WebServer 的本地实例。这样我就可以调用与“服务器”对象所在的那个(不同的)类相关的函数。我误解了这个吗?我担心的是你的陈述“当构造函数离开时被破坏”
  • @Rockclimber399 ESP8266WebServer server(port); 在构造函数中是一个普通的变量定义,因为它也可以在任何其他函数中。当函数返回时,变量被销毁。名为server类成员 与作为其中一部分的CServer 类实例一样长,它在CServer 的类定义中用ESP8266WebServer server; 声明,而不是在构造函数中.
  • 在构造函数中,您可以简单地通过其名称server 访问它(如果您不使用另一个声明隐藏它),就像您在其他成员函数中所做的那样。数据成员的初始化器(即您放错位置的变量定义中的 (port) 部分)必须放在由数据成员名称引入的成员初始化器列表(构造函数中 : 之后的东西)中。如果您按照我展示的方式更改了构造函数,那么 Peter 提到的和您担心的问题就解决了。
  • 我想我明白了。澄清。我声明“ESP8266WebServer server(port);”的方式最初,创建了该类的一个本地实例,该实例可以在我的 CServer 对象的构造过程中出于某种原因使用,但在构造函数返回我的对象​​实例时被销毁。以您提到的方式声明它,引用我想要的“服务器”,在 .h 文件中引用。意思是,后一种方法将使 Server 实例保持活动状态,只要该 CServer 实例还活着。是吗?我可以创建两个 CServer 对象,有两个端口和两个 ESP...服务器也会存在吗?
  • @Rockclimber399 是的,正确。 (除了构造函数并没有真正返回任何东西。它在给定的内存位置(由隐式this指针的值给出)构造一个对象)
猜你喜欢
  • 2021-06-19
  • 2013-07-23
  • 2020-01-22
  • 1970-01-01
  • 2021-09-21
  • 2016-11-23
  • 2012-05-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多