Just nu i M3-nätverket
Gå till innehåll

Metodpekare och std::map


Onp

Rekommendera Poster

Håller på för fullt med att lära mig C++ och har nu kommit till metodpekare. Håller på med ett litet textbaserat äventyrsspel där jag hade tänkt att när man skriver t.ex. "examine the book" så ska den leta upp metoden "examine" från en lista och exekvera den.

 

Har kommit så här långt:

map<string, void (World::*)(Player*, Item*)> functions;
map<string, void (World::*)(Player*, Item*)>::iterator fiter;

functions["examine"] = &World::Examine;

 

Om det vore en vanlig funktionspekare skulle jag ju exekvera så här:

fiter = functions.find("examine");
fiter->second(player, item);

 

Men hur gör man med metodpekare?

 

 

[inlägget ändrat 2004-07-03 18:31:55 av Onp]

Länk till kommentar
Dela på andra webbplatser

En pekare till en metod i C++ är bara knuten till en metod, inte till ett specifikt objekts metod. Detta förklarar sig självt om man tänker på hur klasser och dess data och metoder implementeras i C++. Du måste alltså ropa på metoden genom en instans av din klass "World".

http://www.function-pointer.org/ innehåller en hel del nyttig information.

Lycka till! Funktionspekare / metodpekare gör alltid världen lite roligare!

 

Länk till kommentar
Dela på andra webbplatser

Kanske följande lilla exempel hjälper (om det nu verkligen är funktionspekare du vill åt):

 

#include <stdio.h>

class World {
public:
 static void Examine(int x) {
   printf("In examine, x=%d.\n", x);
 }
};


int
main(int argc, char**argv) 
{
 void (*p)(int) = &World::Examine;
 (*p)(42);
 return 0;
}

 

~/private> g++ x.cc

~/private> ./a.out

In examine, x=42

 

[inlägget ändrat 2004-07-05 11:58:50 av pa9876]

Länk till kommentar
Dela på andra webbplatser

Hm. Jag måste nog använda mig av iterators eftersom jag inte vet namnet på metoden som ska anropas. Sen min fråga var nog egentligen hur syntaxen ser ut för metodpekare kontra funktionspekare. Gärna ett exempel där metodpekaren ingår i en std::map...

 

Länk till kommentar
Dela på andra webbplatser

Precis som pa9876 visar i sitt exempel kan en statisk metod anropas genom en vanlig funktionspekare. Om mandock inte vill ha metoden statisk måste metoden anropas genom en instans av en klass.

I följande exempel stoppar jag in två metodpekare i en map och anropar dessa genom en iterator:

 

#include <map>

#include <string>

#include <iostream>

 

using namespace std;

 

class World {

public:

void examine() { cout << "This is examine()" << endl; }

void draw() { cout << "This is draw()" << endl; }

};

 

 

int main() {

World w;

typedef map<string, void(World::*)()> map_type;

map_type m;

 

m["examine"] = &World::examine;

m["draw"] = &World::draw;

 

for (map_type::iterator itr = m.begin(); itr != m.end(); ++itr) {

cout << itr->first << ": ";

(w.*itr->second)();

}

 

return 0;

}

 

 

Lycka till!

 

Länk till kommentar
Dela på andra webbplatser

Tackar! Det var just (w.*itr->second)(); som var det knepigaste. Förstår inte riktigt logiken i den syntaxen, men men. Det funkar.

 

Nu till nästa fråga =)

Hur gör man om metoderna har olika parametrar?

 

class World {
public:
void examine(Item* item) { item->SomeMethod(); }
void open(Door* door) { door->SomeOtherMethod(); }
};

 

Jag antar att templates har något med det här och göra.

 

[inlägget ändrat 2004-07-05 18:46:33 av Onp]

Länk till kommentar
Dela på andra webbplatser

Kommer inte på något sådär direkt hur du skulle kunna göra det på ett snyggt och säkert sätt. Du skulle ju kunna "someFunction()" vara en en metod i en gemensam abstrakt basklass (till Door och Item) och bara ta en basklasspekare till metoderna. Detta blir säkert och C++ mässigt, fast det kanske inte riktigt passar i i din design.

En annan metod är att låta metoderna examine och open ta void* som argument och i funktionen kasta void* tillbaka till sin verkliga typ. Detta är fult, C-mässigt och osäkert.

Ska fundera lite på hur det skulle kunna göras med templates...

 

Länk till kommentar
Dela på andra webbplatser

Testade följande men får kompileringsfel...

 

metodpekare-3.cc: In function `int main()':

metodpekare-3.cc:55: error: parse error before `*' token

metodpekare-3.cc:56: error: parse error before `*' token

metodpekare-3.cc:60: error: too many arguments to function

metodpekare-3.cc:62: error: too many arguments to function

 

[log]

#include <map>

#include <string>

#include <iostream>

 

using namespace std;

 

class Item {

public:

virtual void doStuff() { cout << "Generic Item doStuff" << endl; }

};

 

class Door : public Item {

public:

void doStuff() { cout << "Door doStuff"; }

};

 

class Window : public Item {

public:

void doStuff() { cout << "Window doStuff"; }

};

 

class World {

public:

World(int id) :id(id) { }

virtual void examine(Item* item) { cout << "This is examine(), id=" << id << ": "; item->doStuff(); cout << endl; }

virtual void draw(Item* item) { cout << "This is draw(), id=" << id << ": "; item->doStuff(); cout << endl; }

int getId() { return id; }

private:

int id;

};

 

class World1 : public World {

public:

World1(int id) : World(id) {}

void examine() { cout << "This is World1::examine(), id=" << getId() << endl; }

void draw() { cout << "This is World2::draw(), id=" << getId() << endl; }

};

 

class World2 : public World {

public:

World2(int id) : World(id) {}

void examine() { cout << "This is World2::examine(), id=" << getId() << endl; }

void draw() { cout << "This is World2::draw(), id=" << getId() << endl; }

};

 

int main() {

World* w1 = new World1(17);

World* w2 = new World2(32);

Item* i1 = new Door();

Item* i2 = new Window();

 

typedef map<string, void(World::*)()> map_type;

map_type m;

 

m["examine"] = &World::examine(Item*);

m["draw"] = &World::draw(Item*);

 

for (map_type::iterator itr = m.begin(); itr != m.end(); ++itr) {

cout << itr->first << ": ";

(w1->*itr->second)(i1);

cout << itr->first << ": ";

(w2->*itr->second)(i2);

}

 

return 0;

}

[/log]

 

Länk till kommentar
Dela på andra webbplatser

Hehe. Har kanske gett mig in på lite för komplicerade områden... men hur ska man annars lösa det? I spelet kan man ju skriva in olika saker, typ "take the knife", "talk to john", etc...

 

Det som händer då är ju att den ska använda metoderna Take() och Talk() från en klass. Men Take() tar ju en Item* som parameter, och Talk() tar ju en Actor* som parameter..

 

Några alternativ?

 

[inlägget ändrat 2004-07-06 16:49:10 av Onp]

Länk till kommentar
Dela på andra webbplatser

Arkiverat

Det här ämnet är nu arkiverat och är stängt för ytterligare svar.

×
×
  • Skapa nytt...