I'm trying to create a class to abstract some basic behavior of libuv's networking functions.
#define TCP_BACKLOG 256
class _tcp {
uv_tcp_t* tcp = NULL;
public:
~_tcp() { delete tcp; }
void listen_uv_listen_uv_connection_cb(uv_stream_t* stream, int status) {
printf("NEW CONNECTION\n");
}
void listen(const char* host, int port) {
tcp = new uv_tcp_t();
uv_tcp_init(uv_default_loop(), tcp);
sockaddr_in* addr = new sockaddr_in();
uv_ip4_addr(host, port, addr);
uv_tcp_bind(tcp, (const sockaddr*)addr, 0);
delete addr;
uv_listen((uv_stream_t*)tcp, TCP_BACKLOG, listen_uv_listen_uv_connection_cb);
}
};
The problem with the previously shown code is that when I try to compile it I get the following error:
error: reference to non-static member function must be called
on: uv_listen((uv_stream_t*)tcp, TCP_BACKLOG, listen_uv_listen_uv_connection_cb);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
And it points to listen_uv_listen_uv_connection_cb as the culprit.
Can someone explain to me, why is that an error, and how am I supposed to fix it?
The uv_listen() and uv_connection_cb signatures are declared as follows
UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb);
typedef void (*uv_connection_cb)(uv_stream_t* server, int status);
You cannot convert non-static member function to a pointer to function even with the same signature, as technically member function has a hidden parameter called this. One of the solution is to make listen_uv_listen_uv_connection_cb static:
class _tcp {
uv_tcp_t* tcp = NULL;
public:
~_tcp() { delete tcp; }
static void listen_uv_listen_uv_connection_cb(uv_stream_t* stream, int status) {
printf("NEW CONNECTION\n");
}
void listen(const char* host, int port) {
tcp = new uv_tcp_t();
uv_tcp_init(uv_default_loop(), tcp);
sockaddr_in* addr = new sockaddr_in();
uv_ip4_addr(host, port, addr);
uv_tcp_bind(tcp, (const sockaddr*)addr, 0);
delete addr;
uv_listen((uv_stream_t*)tcp, TCP_BACKLOG,
&_tcp::listen_uv_listen_uv_connection_cb);
}
};
PS to be able to call a non-static method you would need a way to get a pointer to your _tcp instance from "uv_stream_t* stream" parameter. I would suggest to use "void* uv_handle_t.data" pointer from this doc http://docs.libuv.org/en/latest/handle.html#c.uv_handle_t
static void listen_uv_listen_uv_connection_cb(uv_stream_t* stream, int status) {
_tcp *tcp = static_cast<_tcp *>( stream->data );
tcp->regularMethod();
}
Of course you should assign this pointer to uv_handle_t.data when you initialize uv_tcp_t *:
void listen(const char* host, int port) {
tcp = new uv_tcp_t();
uv_tcp_init(uv_default_loop(), tcp);
tcp->data = this; // do not forget it
...
}
and I would move this initialization code to constructor.
You would need such static wrapper for every callback you are going to use with this library. With c++11 you probably can use lambda instead.
The uv_listen() call back connector expects a static or free (outside class) function.
Thus you should declare your function like this
static void listen_uv_listen_uv_connection_cb(uv_stream_t* stream, int status) {
printf("NEW CONNECTION\n");
_tcp* thisStream = static_cast<_tcp*>(stream);
}
Well, the static_cast<> actually requires your _tcp class inherits from uv_stream_t
class _tcp : public uv_stream_t {
// ...
};
To extend on your comment
"Could you please explain to me why does uv_listen expects a static function? Is this the behavior for all function pointer parameters?"
There's a difference made between class member function pointers, that need to be bound to a class instance for calling, and plain function pointers, that work for any function definition.
Why uv_listen() expects a plain function pointer, is hard to tell. May be because it's a native C-API (I actually don't know it), or for sake of flexibility.
NOTE: You should not use leading underscores for any symbols (as in class _tcp)!
void listen_uv_listen_uv_connection_cb(uv_stream_t* stream, int status) {
printf("NEW CONNECTION\n");
}; <<<<<remove ;
There should be no semicolon at the end of function definition.
And you should write constructor/copy ctr/assign operator for this class.
Related
I have a class:
class SendData
{
public:
SendData(int SendAMsg(int foo, unsigned char *bar, int length), int number)
{
m_nDefinePos = 0;
m_nOtherStuffDefinedAs =0;
}
void somestuffhere();
void ClearDefinition();
private:
int aLotOfVariableshere;
int m_nDefinePos;
};
This is the class itself. Then some stuff is called:
SendData* m_pData;
m_pData->ClearDefinition();
Which now calls this one:
void SendData::ClearDefinition()
{
printf("Welcome to Clear Definition Script\n");
m_nDefinePos = 0;
// Some more stuff here
}
Here the code breaks somehow. I get the "Welcome to Clear Definition Script" message in my console, but that's all.
It breaks on m_nDefinePos = 0;. (I did put in another printf command after it, never showed in the console.)
I just don't know why it breaks there and i cant find any error.
SendData* m_pData;
m_pData->ClearDefinition();
This declares a pointer, but doesn't create an object or initialise the pointer to point to anything, so calling a member function via the pointer will go wrong. Perhaps you wanted to create an object:
SendData data(arguments);
data.ClearDefinition();
or perhaps you wanted to initialise the pointer to point an object that already exists:
SendData* m_pData = whatever;
I have an event handler function and in that function there is a call to a member function of a class. The event handler function is declared in the class cpp file but not part of the class, it's no a member function.
When i compile the code the compiler says that the function is note in the scope, because it's calling a member function within the global event handler function.
My question is as followed: is there a way to use a meber function in a global function? (The object is created first on runtime).
Below is the member function and global event handler:
Global event handler:
void adbEventHandler(Connection * connection, adb_eventType event, uint16_t length, uint8_t * data)
{
Serial.println("In data recieve handler");
Serial.println("Data recieved: ");
Serial.println(data[0]);
Serial.println(data[1]);
char a = data[0];
char b = data[1];
Serial.println(a);
Serial.println(b);
//uint16_t data2 = data;
// Member function of USBCommunicator class
SendBuffer(data, sizeof(data));
}
Member function:
void CommunicationModuleUSB::SendBuffer(uint8_t * Buffer, int Size){
connection->write(Size,(uint8_t*)&Buffer);
}
Update
With the reply of Daniel (thank you!) i changed the member function in the header file and cpp file to static as followed:
static void CommunicationModuleUSB::SendBuffer(uint8_t* Buffer, int Size);
And the function is called in the global eventhandler as followed:
// Event handler for shell connection; called whenever data sent from Android to Microcontroller
void adbEventHandler(Connection * connection, adb_eventType event, uint16_t length, uint8_t * data)
{
Serial.println("In data recieve handler");
Serial.println("Data recieved: ");
//Serial.println(*data);
Serial.println(data[0]);
Serial.println(data[1]);
char a = data[0];
char b = data[1];
Serial.println(a);
Serial.println(b);
//uint16_t data2 = data;
CommunicationModuleUSB::SendBuffer(data, sizeof(data));
}
Only now i get the following error when i compile:
C:\Users\Gebruiker\Documents\Arduino\libraries\CommunicationModuleUSB/CommunicationModuleUSB.h:26: error: extra qualification 'CommunicationModuleUSB::' on member 'SendBuffer.
Does anybody have a idea who to solve that?
Update 2
Thanks again Daniel for your reply!
I have changed the member function with your feedback. But now i get the following error:
C:\Users\Gebruiker\Documents\Arduino\libraries\CommunicationModuleUSB\CommunicationModuleUSB.cpp:77: error: cannot declare member function 'static void CommunicationModuleUSB::SendBuffer(uint8_t*, int)' to have static linkage
I have made the Connection variable static in the header file. Bellow is the header file and the function deffenition form the cpp file.
Do you (or someone else) have any clue? All suggestions are welcome!
Header file:
#include "CommunicationModule.h"
#include <SPI.h>
#include <Adb.h>
class CommunicationModuleUSB : public CommunicationModule
{
public:
CommunicationModuleUSB();
int Connect();
void Send();
int CheckConnection();
void Recieve();
static void SendBuffer(uint8_t* Buffer, int Size);
void RecieveBuffer(char Buffer[], int Size);
// Adb connection made this static....(is this right?
static Connection * connection;
// Elapsed time for sensor sampling
long lastTime;
private:
};
The function decleration in the cpp file:
static void CommunicationModuleUSB::SendBuffer(uint8_t* Buffer, int Size){
connection->write(Size,(uint8_t*)&Buffer);
}
And the call in the global function:
CommunicationModuleUSB::SendBuffer(data, sizeof(data));
Update 3
I have updated te code with the help of Daniel, the only problem that i have now is that the Connection variable that is declared in the class is not in the scope anymore.
The compiler error that i get is as followed:
C:\Users\Gebruiker\Documents\Arduino\libraries\CommunicationModuleUSB/CommunicationModuleUSB.cpp:79: undefined reference to CommunicationModuleUSB::connection'
C:\Users\Gebruiker\Documents\Arduino\libraries\CommunicationModuleUSB/CommunicationModuleUSB.cpp:79: undefined reference toCommunicationModuleUSB::connection'
CommunicationModuleUSB\CommunicationModuleUSB.cpp.o: In function CommunicationModuleUSB::Connect()':
C:\Users\Gebruiker\Documents\Arduino\libraries\CommunicationModuleUSB/CommunicationModuleUSB.cpp:53: undefined reference toCommunicationModuleUSB::connection'
C:\Users\Gebruiker\Documents\Arduino\libraries\CommunicationModuleUSB/CommunicationModuleUSB.cpp:53: undefined reference to `CommunicationModuleUSB::connection'
The connection variable is declared in the header file as followed:
// Adb connection made this static....(is this right?
static Connection * connection;
The variable is used in the following member functions:
void CommunicationModuleUSB::SendBuffer(uint8_t* Buffer, int Size){
connection->write(Size,(uint8_t*)&Buffer);
}
And is used in the following global event handler function:
// Event handler for shell connection; called whenever data sent from Android to Microcontroller
void adbEventHandler(Connection * connection, adb_eventType event, uint16_t length, uint8_t * data)
{
Serial.println("In data recieve handler");
Serial.println("Data recieved: ");
Serial.println(data[0]);
Serial.println(data[1]);
char a = data[0];
char b = data[1];
Serial.println(a);
Serial.println(b);
CommunicationModuleUSB::SendBuffer(data, sizeof(data));
}
Doe anybody have a suggestion how to solve this?
Member function is a member function and that is for a reason. You are calling SendBuffer() as if it was ordinary function defined in a global scope, which it is not. You can call member function in two ways.
First: You create a instance of a class and then you call the method:
CommunicationModuleUSB cm();
cm.SendBuffer(data, sizeof(data));
Second: You make the method static so the signature is as follows:
static void CommunicationModuleUSB::SendBuffer(uint8_t * Buffer, int Size);
So declaration would look like so:
class CommunicationModuleUSB
{
//Other stuff
static void SendBuffer(uint8_t * Buffer, int Size);
//Other stuff
}
and your definition of the function:
void CommunicationModuleUSB::SendBuffer(uint8_t * Buffer, int Size)
{
//Your code
}
Now you can call it like this:
CommunicationModuleUSB::SendBuffer(data, sizeof(data));
BUT this has more implications. Making the method static allows it to access only static member variables of the class as it does not belong to any particular object. This, however, makes sense as calling a method that belongs to a particular object is just the same as calling eat() method of Carrot that doesn't yet exist.
I'm having trouble with this function below:
char* GetPlayerNameEx(int playerid)
{
char Name[MAX_PLAYER_NAME], i = 0;
GetPlayerName(playerid, Name, sizeof(Name));
std::string pName (Name);
while(i == 0 || i != pName.npos)
{
if(i != 0) i++;
int Underscore = pName.find("_", i);
Name[Underscore] = ' ';
}
return Name;
}
declaration:
char* GetPlayerNameEx(int playerid);
usage:
sprintf(string, "%s", CPlayer::GetPlayerNameEx(playerid));
Now my problem here is
Removed personal information.
If this has anything to do whith it which I doubt it does, this function is contained within a "Class" header (Declartion).
Also I have no idea why but I can't get the "Code" box to fit over correctly.
Illegal call of non-static member function means that you are trying to call the function without using an object of the class that contains the function.
The solution should be to make the function a static function.
This is normally what causes the error C2352:
class MyClass {
public:
void MyFunc() {}
static void MyFunc2() {}
};
int main() {
MyClass::MyFunc(); // C2352
MyClass::MyFunc2(); // OK
}
If making it static is not an option for you, then you have to create an instance of the class CPlayer.
Like this:
CPlayer myPlayer;
myPlayer.GetPlayerNameEx(playerid);
You cannot create these functions as static (without a lot of tweaking) because you are attempting to modify the data of a specific instance. To fix your problem:
class CPlayer
{
public:
// public members
// since you are operating on class member data, you cannot declare these as static
// if you wanted to declare them as static, you would need some way of getting an actual instance of CPlayer
char* GetPlayerNameEx(int playerId);
char* GetPlayerName(int playerId, char* name, int size);
private:
// note: using a std::string would be better
char m_Name[MAX_PLAYER_NAME];
};
// note: returning a string would be better here
char* CPlayer::GetPlayerNameEx(int playerId)
{
char* Name = new char[MAX_PLAYER_NAME];
memset(Name, MAX_PLAYER_NAME, 0);
GetPlayerName(playerId, m_Name, sizeof(m_Name));
std::string sName(m_Name);
std::replace(sName.begin(), sName.end(), '_', ' ');
::strncpy(sName.c_str(), Name, MAX_PLAYER_NAME);
return Name;
}
// in your usage
CPlayer player;
// ...
sprintf(string, "%s", player.GetPlayerNameEx(playerid));
CPlayer::GetPlayerNameEx(playerid)
You can't use the scope (::) operator on a class type to call a function unless it is a static function. To call a function on an object, you actually have to create the memory for that object first (via making a CPlayer variable somewhere) and then calling the function on that object.
Static functions are global and specifically do not mess with member variables of the class (unless they are also static) which makes them valid to call without the scope of an actual object instance.
This question already has answers here:
pthread function from a class
(9 answers)
Closed 9 years ago.
I have a class named qwerty and a function called compute_ans inside it which takes a void pointer and returns a void pointer. Now when I try to compile, the following statement throws an error
pthread_create (thread_a, NULL, compute_ans, (void*) struct_left);
The definition of the function is void* compute_ans (void* struct_input)
The error is
cannot convert ‘qwerty::compute_ans’ from type ‘void* (qwerty::)(void*)’ to type ‘void* ()(void)’*
You cannot convert a pointer to a non-static member function to a pointer to function, C++ does not allow it. The reason is that member functions take an implicit this pointer as a parameter. Essentially this changes the signature of your function to be something like void* compute_ans(qwerty*, void*). In order to pass the function to pthread_create you need to make the member function static.
class qwerty
{
public:
// ... other member functions and variables ...
// thread start function
static void* compute_ans(void*);
};
If you cannot make this a static member function you will need to pass a pointer to a qwerty object to the thread start function. Looking at the code in your question you also need to pass additional data to the thread function. To do this you can use an additional data structure that contains all the necessary data and pass a pointer to that instead.
class qwerty; // forward declaration
// Structure passed to pthread_create and our helper function
struct thread_data
{
qwerty* qptr; // pointer to qwerty object
void* data; // pointer to other data. change void to your data type.
};
class qwerty
{
public:
// thread start function
static void* start_compute_ans(void* param)
{
// get a pointer to the thread data
thread_data* tdata = static_cast<thread_data*>(param);
// Call the real compute_ans
tdata->qptr->compute_ans(tdata->data);
// Delete the data (use an appropriate smart pointer if possible)
delete tdata;
return NULL;
}
// the real
void compute_ans(void*)
{
// do stuff here
}
};
// Create our thread startup data
thread_data* tdata = new thread_data();
tdata->qptr = qwerty_pointer;
tdata->data = struct_left;
// start the thread data
pthread_create (thread_a, NULL, &qwerty::start_compute_ans, tdata);
You can find the answer here.
You should use static functions to pass to pthread.
class qwerty
{
public:
void compute_ans(void)
{
std::cout << "Compute result!" << std::endl;
return
}
static void hello_helper(void *context)
{
return ((qwerty *)context)->compute_answer();
}
};
...
qwerty c;
pthread_t t;
pthread_create(&t, NULL, &qwerty::hello_helper, &c);
I have been beating my head around this issue of static versus non-static, callback functions, function pointers, etc... My goal is to access data of a struct outside the scope of my callback interface. I am trying to do this within my class called TextDetect. I thought I was on track when I asked this question: Avoiding a static member function in c++ when using a callback interface from C
However, I still can't access the data without losing scope over the data that I am most interested. At runtime, I get "Access violation reading location ..." I'll point it out below where it fails.
I implemented the answer to my previous question as the following class, shown entirely (Note: vtrInitialize is part of a 3rd party api code int vtrInitialize(const char *inifile, vtrCallback cb, void *calldata);):
class TextDetect {
const char * inifile;
vtrImage *vtrimage;
int framecount;
public:
TextDetect();
~TextDetect();
void vtrCB(vtrTextTrack *track);
static void vtrCB_thunk(vtrTextTrack *track, void *calldata);
int vtrTest(cv::Mat);
bool DrawBox(cv::Mat&);
vtrTextTrack *texttrack;
};
TextDetect::TextDetect() : inifile("vtr.ini")
{
if (vtrInitialize(inifile, vtrCB_thunk, static_cast<void *>(this) ) == -1)
std::cout << "Error: Failure to initialize" << std::endl;
vtrimage = new vtrImage;
}
int TextDetect::vtrTest(cv::Mat imagetest)
{
/*store image data in an image structure*/
}
void TextDetect::vtrCB(vtrTextTrack *track)
{
/*send data to command line from callback */
I've tried copying the data I need a variety of ways and nothing works (this code is a continuation from above):
//texttrack = track;
//texttrack = new vtrTextTrack (*track);
memcpy(texttrack,track,sizeof(*track));
//vtrTextTrackFree(track);
}
void TextDetect::vtrCB_thunk(vtrTextTrack *track, void *calldata)
{
static_cast<TextDetect *>(calldata)->vtrCB(track);
}
This is the member function were I want the data to be used. Texttrack is public member so I might need it outside my class as well (this code is a continuation from above):
bool TextDetect::DrawBox(cv::Mat& tobeboxed)
{
And I get the access violation error at runtime here at this line of code (this code is a continuation from above):
if (texttrack->best->ocrconf > 90)
{
/*do some more stuff*/
}
}
Hopefully I'm understanding this correctly.
It seems to me that the problem is trying to copy those vtrTextTrack structs improperly.
This:
//texttrack = track;
just copies the pointer. If the owner of the struct (probably the caller of the callback function) destroys/deletes the vtrTextTrack, then you're holding on to an invalid pointer.
This one:
memcpy(texttrack,track,sizeof(*track));
will copy all the members of the vtrTextTrack, but will not copy what's being pointed to by it's member pointers (e.g. texttrack->best). Again, if the owner destroys/deletes the track, then you're holding on to invalid pointers.
And since
//texttrack = new vtrTextTrack (*track);
didn't work, I'm guessing that vtrTextTrack doesn't provide a copy constructor.
As for a workaround, first check if your third party library provides a function to copy these structs. If that's not the case (could this be by design?), then you may have to implement one yourself. This might be hard because there might be all kinds of internals that you don't know about. If you don't need the whole vtrTextTrack, I'd say define another struct and store only the information you need. Something along the lines of
SomeType* bestCopier(SomeType* src)
{
SomeType* temp;
/* copy over struct */
return temp;
}
Foo* fooCopier(Foo* src)
{
/*...*/
}
struct myTextTrack
{
public:
myTextTrack(vtrTextTrack* src)
{
//copy over stuff
m_best = bestCopier(src->best);
m_foo = fooCopier(src->foo);
}
private:
/* the members you care about*/
SomeType* m_best;
Foo * m_foo;
}