8

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.

user1591117
  • 287
  • 2
  • 5
  • 13
  • 1
    You have [undefined behaviour](http://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope). I would return a `std::string` anyway. – chris Aug 22 '13 at 00:50
  • Is the function GetPlayerNameEx declared inside CPlayer namespace or is CPlayer the class name? – Amadeus Aug 22 '13 at 00:53
  • 1
    @chris: according to the compiler, the OP's program is in fact ill-formed. For an undefined behavior to occur, it must necessarily compile and run first. – Igor Tandetnik Aug 22 '13 at 00:53
  • You have to declare that function `static`. – Banex Aug 22 '13 at 00:53
  • The code is suppost to remove the underscore from "Name", I can't return pName. – user1591117 Aug 22 '13 at 00:53
  • Also CPlayer is the class. declaring static char* doesn't work, at all, it just returns the same errors and library errors. – user1591117 Aug 22 '13 at 00:55
  • @IgorTandetnik, That's twice now. I need to stop thinking ahead. – chris Aug 22 '13 at 00:56
  • You need an instance of the `CPlayer` class before you can call methods on it. – Adam Rosenfield Aug 22 '13 at 00:57
  • Adam, the CPlayer class is included in main.h; I am trying to call this from main.cpp thus there should be an instance. I have an idea of the problem no I come to think of it... – user1591117 Aug 22 '13 at 01:04
  • You can't return a pointer to a local array. Why not return `std::string` instead? – Neil Kirk Aug 22 '13 at 01:36

3 Answers3

11

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);
Jiddle
  • 217
  • 2
  • 7
  • The scope operator is used when you need to call a static function, so it the OP declared that function as static it should work. – Banex Aug 22 '13 at 00:58
  • Banex declaring as static decided to return the same errors, which is why I'm confused. the -> fundtion aswell returns similar errors. When I use :: the function appears in the drop down. – user1591117 Aug 22 '13 at 01:01
  • @user1591117 be sure to put the static keyword only in the header where the class declaration is. – Banex Aug 22 '13 at 01:04
  • The scope operator is more specifically a way to declare which scope you are using for the next statement, not necessarily only for calling static methods. – Lochemage Aug 22 '13 at 01:07
  • You can't make the function static if it calls another non-static function or uses a non-static variable inside it. – Lochemage Aug 22 '13 at 01:11
  • if you mean: static char* GetPlayerName(int playerid); which I do on both the declaration and in the Players.cpp file, I have done this to no avail it seems determined to return that error plus a library error when I do. – user1591117 Aug 22 '13 at 01:12
  • You're right, the GetPlayerName() function needs to be static too in that case: That would probably remove the error, but maybe that isn't an option for you? Will keep looking into it. @user1591117 You should only declare the function as static in the header, as shown in my example. – Jiddle Aug 22 '13 at 01:14
  • Just to clarify my function can't be "void", it is required to return a char* as GetPlayerName(), default insists on returning a char* which altering that would thus means the SDK would no execute the natives I require. – user1591117 Aug 22 '13 at 01:15
  • Jiddle: as stated either way it gives me a very depressing Library Linker error once doing this. The header is included, the error only occurs when I try to place a static infront of it. unresolved external symbol "public: static char * __cdecl CPlayer::GetPlayerNameEx(int)" (?GetPlayerNameEx@CPlayer@@SAPADH@Z) referenced in function _OnPlayerConnect@4 – user1591117 Aug 22 '13 at 01:19
  • To make it static, declare it `static char* GetPlayerNameEx(int playerid);` then define it as `char* CPlayer::GetPlayerNameEx(int playerid) {...}`. But again, make sure it does not call or use any non-static variable/method inside it. – Lochemage Aug 22 '13 at 01:22
  • As @Lochemage is trying to say: Be aware that you are calling the non static function GetPlayerName() inside the static function GetPlayerNameEx() Which is not allowed. – Jiddle Aug 22 '13 at 01:25
5

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));
Zac Howland
  • 15,777
  • 1
  • 26
  • 42
  • This removes the static error, however gives me conversation errors. I'm sure I can tweak and work with this. Thanks :D. – user1591117 Aug 22 '13 at 01:27
  • Okay untested however I have got this working thanks to the code your posted; thanks for yours and everybody help here. :D – user1591117 Aug 22 '13 at 01:38
  • @Neil: True. I didn't fix that (was focused on the static issue). I'll correct that for completeness. – Zac Howland Aug 22 '13 at 01:49
2
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.

Lochemage
  • 3,974
  • 11
  • 11
  • Yes, using -> is de-referencing the object, you can't do that on a class type, you actually have to make the object first. `CPlayer* myPlayer = new CPlayer; myPlayer->GetPlayerNameEx(playerid);` would work, but it sounds to me like that function should just be static, as it doesn't really care what player is invoking it. – Lochemage Aug 22 '13 at 01:03
  • @Lochemage, Except it would use pointers quite unnecessarily. – chris Aug 22 '13 at 01:05
  • @Lochmage: That's exactly what I don't understand as any playerid I enter it should process it. Would making this global illuminate the problem, as I'm happy to do that; however it then would require redefining quite a but of code. – user1591117 Aug 22 '13 at 01:10
  • @chris I was only explaining why he can't use -> on the class type and how -> can be used to invoke the function, not that he should. I even state at the end that it's more likely he intended to use static judging by what his function seems to be for. – Lochemage Aug 22 '13 at 01:15
  • @user1591117 you use static methods in the case when it doesn't matter what particular object you are doing it on or in the case where you don't intend to make the object. For example, if your `CPlayer` class is particularly just ONE player, and your function is meant to search ALL players regardless of which player called that function, then yes, you want it static. But if you ONLY want that function to react on the actual player that's calling it, then you don't. – Lochemage Aug 22 '13 at 01:18