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.
Related
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.
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 want to pass a class object into a method of other class through a thread call, I tried but got the error can any one help me on this.please.
struct sample{
int status;
std::vector <std::string> a_row;
size_t column_count;
std::vector <std::string> column;
};
class sess {
public:
int a;
sess(int);
sess();
};
class Gen {
private:
static Gen* gen_obj;
public:
static bool Gen_InstanceFlag;
static Gen* GetInstance();
sample addition(sess);
};
/* End of Header File */
/* Beginning of cpp File */
include"Class_thread_mixing.h"
bool Gen::Gen_InstanceFlag=false;
Gen* Gen::GetInstance(){
if(!Gen::Gen_InstanceFlag){
Gen::gen_obj = new Gen();
Gen::Gen_InstanceFlag= true;
return gen_obj;
}
else {
return gen_obj;
}
}
sample addition(sess ses_obj){
sample sam;
sam.a_row.push_back("success");
sam.column.push_back("result");
sam.column_count=1;
sam.status=ses_obj.a;
return sam;
}
int main(int argc, char* argv[])
{
HANDLE myhandleA;
Gen* gen=Gen::GetInstance();
sess ses_obj(10);
myhandleA=(HANDLE)_beginthreadex(0, 0, gen->addition(ses_obj),(void*)0, 0, 0);
WaitForSingleObject(myhandleA, INFINITE);
CloseHandle(myhandleA);
getchar();
return 0;
}
This is my code and I am getting an error like "error C2665: '_beginthreadex' : none of the 2 overloads could convert all the argument types"
Can any one suggest me who can I pass the object of sess to a function in a thread call and how can I get the results from the thread.
Thanks for your answers..
s there any option such that I can call the function directly in the thread without calling a standalone thread function, like I mentioned in my code [(HANDLE)_beginthreadex(0, 0, gen->addition(ses_obj),(void*)0, 0, 0) ]
I need to call addition method in the thread can any body help me on this.
The problem here is that instead of passing a function to the called by _beginthreadex, you are actually calling that function with an argument, causing the _beginthreadex function to be called with the return value from Gen::addition. This structure is if course not a function, and so the compiler complains.
The solution to this is not straightforward though. First of all because a stand-alone function (as required by _beginthreadex is not the same as a class member function. The reason being that all class member functions actually have a "zeroeth" hidden argument, and that is an instance of the class that becomes the this pointer that can be used inside member functions.
The best solution is probably to create a stand-alone function, which takes as argument a pointer to a structure, and the structure contains the object instance, and the argument to the actual member function.
Something like this:
struct call_data
{
sess sess_obj;
Gen* gen_obj;
};
static void thread_function(void* data)
{
call_data *call = reinterpret_cast<call_data*>(data);
// Do the actual member function call
call->gen_obj->addition(call->sess_obj);
}
int main()
{
...
call_data call = { ses_obj, gen };
myhandleA=(HANDLE)_beginthreadex(0, 0, thread_function, &call, 0, 0);
...
}
Entry point for thread can't be a class method. it has to be static or at global scope.
You need to define a static method like this
static unsigned ThreadEntry(void* arg)
{
sess *p = (sess*)arg;
Gen::GetInstance()->addition(*p);
}
and run the thread like this:
sess ses_obj(10);
myhandleA=(HANDLE)_beginthreadex(0, 0, ThreadEntry,(void*)&ses_obj, 0, 0);
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.
I would like someone to shed some light this code snippet, which confuses me.
//-------------------------------------------------------------------------------
// 3.5 Example B: Callback to member function using a global variable
// Task: The function 'DoItB' does something that implies a callback to
// the member function 'Display'. Therefore the wrapper-function
// 'Wrapper_To_Call_Display is used.
#include <iostream.h> // due to: cout
void* pt2Object; // global variable which points to an arbitrary object
class TClassB
{
public:
void Display(const char* text) { cout << text << endl; };
static void Wrapper_To_Call_Display(char* text);
/* more of TClassB */
};
// static wrapper-function to be able to callback the member function Display()
void TClassB::Wrapper_To_Call_Display(char* string)
{
// explicitly cast global variable <pt2Object> to a pointer to TClassB
// warning: <pt2Object> MUST point to an appropriate object!
TClassB* mySelf = (TClassB*) pt2Object;
// call member
mySelf->Display(string);
}
// function does something that implies a callback
// note: of course this function can also be a member function
void DoItB(void (*pt2Function)(char* text))
{
/* do something */
pt2Function("hi, i'm calling back using a global ;-)"); // make callback
}
// execute example code
void Callback_Using_Global()
{
// 1. instantiate object of TClassB
TClassB objB;
// 2. assign global variable which is used in the static wrapper function
// important: never forget to do this!!
pt2Object = (void*) &objB;
// 3. call 'DoItB' for <objB>
DoItB(TClassB::Wrapper_To_Call_Display);
}
Question 1: Regarding this function call:
DoItB(TClassB::Wrapper_To_Call_Display)
Why does Wrapper_To_Call_Display not take any arguments, although it is supposed to take a char* argument according to its declaration?
Question 2: DoItB is declared as
void DoItB(void (*pt2Function)(char* text))
What I’ve understood so far is that DoItB takes a function pointer as argument, but why does the function call DoItB(TClassB::Wrapper_To_Call_Display) take TClassB::Wrapper_To_Call_Display as argument even tough it’s not a pointer?
Thanx in advance
Source of code snippet: http://www.newty.de/fpt/callback.html
In C/C++ when a function name is used with no parameters - that is no parenthesis - it is a pointer to a function. So TClassB::Wrapper_To_Call_Display is a pointer to the address in memory where the code for the function is implemented.
Since TClassB::Wrapper_To_Call_Display is a pointer to a void function that takes a single char* it's time is void (*)(char* test) so it matches the type required by DoItB.