Passing Functions as arguments(help)

I getting some errors when trying to pass in some functions as arguments. Heres the Code, ive pointed out the key parts to the program which im having trouble(so you wont have to read 300 lines of code) with lines. These marked spots can be seen by the breaks:
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
MAIN.CPP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#include <cstdlib>
#include <string>
#include <fstream>
#include <windows.h>
#include "Map.h"
#include "Player.h"
bool Game = true;
bool pOneTurn = true;
bool pTwoTurn = false;
int main()
{
    Map mObj(2);
    mObj.createmap();
    mObj.SSP();
    mObj.RefreshScreen();
    while(Game){ //while the game is running
        while(pOneTurn){ //player ones turn
            int moves = 0;
            while(moves <5){
                std::cout << "PLAYER ONE w(UP) s(DOWN) a(LEFT) d(RIGHT)\n"; //display controls and stats
                std::cout << "\n --- MOVES LEFT --- " << 5 - moves << std::endl;
                mObj.InputChoice(1); //run input function to see where to move
                mObj.RefreshScreen(); //rewrite the array
                moves++;
            }
            //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
            mObj.callFire(1); //CALLING FUNCTION
            //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
            mObj.RefreshScreen();
            pTwoTurn = true; //set player twos turn to true
            pOneTurn = false; //set player ones turn to false
        }
        while(pTwoTurn){
            int moves=0;
            while(moves < 5){
                std::cout << "PLAYER TWO w(UP) s(DOWN) a(LEFT) d(RIGHT)\n";
                  std::cout << "\n --- MOVES LEFT --- " << 5-moves << std::endl;
                mObj.InputChoice(2);
                mObj.RefreshScreen();
                moves++;
            }
            //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
            mObj.callFire(2); //CALLING FUNCTION
            //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
            mObj.RefreshScreen();
            pOneTurn = true;
            pTwoTurn = false;
        }
    }
}

MAP.H
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef MAP_H
#define MAP_H
#include <string>
#include "Map.h"
#include "Player.h"
#include <vector>
class Map
{
    public:
        void createmap() ;
        void InputChoice(int pN); //pN(Player Number)
        Map(int noP); //number of PLAYERS
        void SSP(); //SET START POSITION
        //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
        void RefreshScreen(); //reprint array
        void cls();
        void callFire(int pN); //call the fire function using map
        //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    private:
        static const int nrows = 20; //array bounds
        static const int ncols = 20;
        char map[nrows][ncols];
        char bgmap[nrows][ncols];
        Player pObj; //a map HAS a player, a player is NOT a map(thanks you guys for that logic, helped A LOT)
        Player ptObj;
};
#endif // MAP_H 

MAP.CPP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include "Map.h"
#include "Player.h"
#include <iostream>
#include <cstdlib>
#include <string>
#include <fstream>
#include <windows.h>
Map::Map(int pN):
pObj(5,5),
ptObj(15,15) //player TWO object
{
}
void Map::SSP() //calls player function
{
            pObj.SetStartPos('B',map);
            ptObj.SetStartPos('O',map);
}
void Map::InputChoice(int pN) //player NUMBER
{
    /* i didnt know how to access the player class outside without making another object to player, so i just made a function that
    calls the object, i need this seperate because i need to call input, THEN cls(), then refresh, in that specific order. Comment if you think i should
    move the refresh function into map aswell to make some giant function that handles it. Problem is i feel like im stuffing to much stuff into Map.h and
    .cpp */
    switch(pN){
        case 1:
            pObj.InputChoice('B',map,bgmap); //calls player functions
            break;
        case 2:
            ptObj.InputChoice('O',map,bgmap);
            break;
    }
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void Map::RefreshScreen() //reprint array
{
    cls();
    for( int nrow = 0; nrow < nrows; nrow++){
            for(int ncol = 0; ncol < ncols;ncol++)
                std::cout << map[nrow][ncol] << " ";
            std::cout << std::endl;
            }
}
void Map::cls() //windows h function to replace screen with nulls
{
  DWORD n;
  DWORD size;
  COORD coord = {0};
  CONSOLE_SCREEN_BUFFER_INFO csbi;
  HANDLE h = GetStdHandle ( STD_OUTPUT_HANDLE );
  GetConsoleScreenBufferInfo ( h, &csbi );
  size = csbi.dwSize.X * csbi.dwSize.Y;
  FillConsoleOutputCharacter ( h, TEXT ( ' ' ), size, coord, &n );
  GetConsoleScreenBufferInfo ( h, &csbi );
  FillConsoleOutputAttribute ( h, csbi.wAttributes, size, coord, &n );
  SetConsoleCursorPosition ( h, coord );
}
void Map::callFire(int pN)
{
    switch(pN){
        case 1:
        //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
            pObj.FireG(RefreshScreen, cls, map, bgmap, pObj.getx(), pObj.gety()); //ERRORS HERE!
        //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
            break;
        case 2:
        //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
            ptObj.FireG(RefreshScreen, cls, map, bgmap,ptObj.getx(),ptObj.gety()); //ERRORS HERE!
        //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
            break;
    }
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void Map::createmap() { //read map in from "Map.txt" file
    using namespace std;
    ifstream MapStruct("Map.txt");
    while(!MapStruct.eof()){
        for( int nrow = 0; nrow < nrows; nrow++){
            for(int ncol = 0; ncol < ncols;ncol++){
                    MapStruct >> map[nrow][ncol];
                    bgmap[nrow][ncol] = map[nrow][ncol];
                }
            }
        }
MapStruct.close(); //close file to prevent leaks
}

PLAYER.H
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#ifndef PLAYER_H
#define PLAYER_H
#include "Map.h"
#include <iostream>
class Player //not much in this class, work in progress
{
    public:
        int getx(){return xp;};
        int gety(){return yp;};
        void wait(int seconds);
        Player(int x, int y); //takes the players coords as parameters
        void InputChoice(char c,char map[][20], char bgmap[][20]); //uses the current map to move across
        void SetStartPos(char c,char map[][20]); //set positions at the start so they are visible
        //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
        void FireG(void (*r)(), void (*c)(),char map[][20], char bgmap[][20], int xcord, int ycord); //fires an X horizontally across the map, uses the map and current player       
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    private:
    int xp;
    int yp;
};
#endif 
Last edited on
PLAYER.CPP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <iostream>
#include <cstdlib>
#include <string>
#include <fstream>
#include <windows.h>
#include "Map.h"
#include "Player.h"
#include <time.h>
Player::Player(int x, int y):
xp(x),
yp(y)
{
}
void Player::InputChoice(char c,char map[][20], char bgmap[][20])
{
        char x;
        std::cin >> x;
         switch(x){
                case 'w' :        //moves 'x' up one and replaces the coord before with what it originally had
                    if(yp <= 0){
                        yp = 0;
                    }else{yp-=1;}
                        map[yp + 1][xp] = bgmap[yp + 1][xp]; //replace last coord with the background map, which stays constant.
                    break;
                case 's':
                    if(yp >= 19){
                        yp = 19;
                    }else{yp+=1;}
                        map[yp - 1][xp] = bgmap[yp - 1][xp];
                    break;
                case 'a':
                    if(xp <= 0){
                        xp = 0;
                    }else{xp -=1;}
                        map[yp][xp + 1] = bgmap[yp][xp + 1];
                    break;
                case 'd':
                    if(xp >= 19){
                        xp = 19;
                    }else{xp +=1;}
                        map[yp][xp - 1] = bgmap[yp][xp - 1];
                    break;
            }
            map[yp][xp] = c; //set current position to 'x', later in this project i will be using a varible when i ask how to put in multiple players
            // and study vectors a little more(lots of learning to do!).
}
void Player::SetStartPos(char c,char map[][20])
{
    map[xp][yp] = c;
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void Player::FireG(void (*r)(), void (*c)(),char map[][20], char bgmap[][20], int xcord, int ycord) //FIRE function
{
    int Path = 1;
    while(map[ycord][xcord + Path] != 'G'){
        xcord += Path;
        map[ycord][xcord] = 'H'; //this is the "Object" the player fires
        wait(3); //wait 3 seconds before refreshing the screen, this function is not completely
        //finished yet, still working on deleting the H's on the map now.
        c(); //Clear the screen
        r(); //Refresh the screen
    }
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void Player::wait ( int seconds )
{
  clock_t endwait;
  endwait = clock () + seconds * CLOCKS_PER_SEC ;
  while (clock() < endwait) {}
}

The Error im getting:
1
2
3
4
5
6
U:\2DimMapv1.03\Map.cpp||In member function 'void Map::callFire(int)':|
U:\2DimMapv1.03\Map.cpp|81|error: no matching function for call to 'Player::FireG(<unresolved overloaded function type>, <unresolved overloaded function type>, char [20][20], char [20][20], int, int)'|
U:\2DimMapv1.03\Player.h|14|note: candidates are: void Player::FireG(void (*)(), void (*)(), char (*)[20], char (*)[20], int, int)|
U:\2DimMapv1.03\Map.cpp|84|error: no matching function for call to 'Player::FireG(<unresolved overloaded function type>, <unresolved overloaded function type>, char [20][20], char [20][20], int, int)'|
U:\2DimMapv1.03\Player.h|14|note: candidates are: void Player::FireG(void (*)(), void (*)(), char (*)[20], char (*)[20], int, int)|
||=== Build finished: 2 errors, 0 warnings ===|
Last edited on
You declare

void Player::FireG(void (*r)(), void (*c)(),char map[][20], char bgmap[][20], int xcord, int ycord);

but when you call it

pObj.FireG(RefreshScreen, cls, map, bgmap, pObj.getx(), pObj.gety());

you pass functions ( RefreshScreen, cls) as arguments that require implicit object parameter (this) because they are non-static function members.
Last edited on

Member functions are a whole different kettle of fish when compared to ordinary function pointers. There's actually very little that member-function-pointers and normal function-pointers have in common except that both represent addresses of callable entities - you can't mix and match them, and unfortunately, member-function-pointers are not particularly elegant to write either.

I'd strongly recommend reading the FAQ entries in the link below, because they explain some of the "quirks" related to member function pointers with a few examples/suggestions on how to use them (and how to avoid them: see the FAQs at the bottom of the page which talk about functionoids)
--> http://www.parashift.com/c++-faq-lite/pointers-to-members.html


As for your problem, I'd suggest that it's probably easier to simply pass a reference to your map object as an argument to FireG (unless you have a burning need to be able to "select" different member functions for your calls to clear and refresh

e.g.
1
2
3
4
5
6
void Player::FireG(Map& screen,char map[][20], char bgmap[][20], int xcord, int ycord) //FIRE function
{
/* etc... */
        screen.cls(); 
        screen.RefreshScreen();
} 


Then when calling FireG:
1
2
3
4
5
    switch(pN){
        case 1:
        //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
            pObj.FireG( *this, map, bgmap, pObj.getx(), pObj.gety());
        //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=  
Last edited on
Thanks for the reply guys, its helped a lot!

Bench82- The problem is i made it so that only one map can be declared(the constructor sets the position of two Player objects). Should i use polymorphism and overload the constructor so that i can create a normal object to access the Map functions? as in another constructor like so:

1
2
3
4
5
Map();

Map::Map()
{
}


Also, why do you use *this? i understand "this" is used to specify what the program should specifically modify(reference or copy) but why is their a deference in-front of it? Is it saying "THIS CLASS" ? Thanks for the help!
It doesn't matter how many Map objects exist. Even if there's only 1 Map object in your entire program, it doesn't stop you passing it to functions by-reference. pass-by-reference doesn't make any copies, it provides direct access to the passed object, so you don't need a copy constructor.


the this keyword is a pointer-to the current object (So, from a member function of Map, this means "pointer-to the current Map object"). Using the de-reference operator * gives you an expression which directly accesses the object.

Typically it's much better to avoid pointers (they're ugly, unsafe, and unnecessary a lot of the time) - references are much nicer - so in dereferencing it, you can pass it to a function which accepts a map argument by-reference. (i.e. Map& )


Note: don't get too hung up on the words "reference" vs. "dereference". It's highly unfortunate that these words are used, because they're not really orthogonal (even though they sound like they should be) - 'dereference' is an operation, whereas 'reference' is a data type.

- Dereference (verb) means to access the object pointed-to by a pointer object
- A reference (noun) is a type of variable which is conceptually very similar to a const/immutable/nonmodifiable pointer variable.


FAQ: http://www.parashift.com/c++-faq-lite/references.html
Last edited on
Wow...that just explained a lot of my questions Ive ever had, you are amazing! Just one more question to annoy you with! I took your idea but im getting the error:
1
2
3
4
F:\2DimMapv1.04A\Player.h|16|error: 'Map' has not been declared|
F:\2DimMapv1.04A\Player.cpp|56|error: prototype for 'void Player::FireG(Map&, char (*)[20], char (*)[20], int, int)' does not match any in class 'Player'|
F:\2DimMapv1.04A\Player.h|16|error: candidate is: void Player::FireG(int&, char (*)[20], char (*)[20], int, int)|
||=== Build finished: 3 errors, 0 warnings ===|

Only change in code is the prototype, and Function header like you gave above. I feel like the program is compiling Player first before map? im completely making this up as i go though, as i have no clue how the compiler takes priority in compiling classes. What am i missing?
Your prototype parameters don't match the actual signature of the function. See them side-by-side:

Source: void Player::FireG(Map&, char (*)[20], char (*)[20], int, int)
Header: void Player::FireG(int&, char (*)[20], char (*)[20], int, int)



edit:
If you happen to get issues with circular declarations, then you can resolve it by sticking a forward declaration at the top of the header file

i.e.
1
2
3
4
5
6
7
8
#ifndef PLAYER_H
#define PLAYER_H

class Map;  // Forward Declaration: compiler knows that 'Map' exists, but doesn't know
            // anything about its size or make-up yet;  Allowed to use it for references + pointers

class Player 
{ 
Last edited on
Topic archived. No new replies allowed.