Anmelden

Archiv verlassen und diese Seite im Standarddesign anzeigen : Zeiger auf Elementmethoden!?



RAHUL
22-11-2005, 11:31
Hallo,

ich habe hier wieder so eine Beispielaufgabe und weiss nicht ob ich wieder
einfach ein blöden kleinen Fehler gemacht habe oder die Aufgabe im Buch nicht richtig
ist.
Hier ist der Code

#include <iostream>
using namespace std;


class Mammal
{
public:
Mammal():itsAge(1) {}
virtual ~Mammal() {}
virtual void Speak() const = 0;
virtual void Move() const = 0;
protected:
int itsAge;
};

class Dog: public Mammal
{
public:
void Speak() const { cout << "Wuff!\n";}
void Move() const {cout << "Bei Fuss gehen...\n";}
};

class Cat: public Mammal
{
public:
void Speak() const { cout << "Miau!\n";}
void Move() const {cout << "Schleichen...\n";}
};

class Horse: public Mammal
{
public:
void Speak() const { cout << "Wieher!\n";}
void Move() const {cout << "Gallopieren...\n";}
};

int main()
{
void (Mammal::*pFunc)() const = 0;
Mammal * ptr = 0;
int Animal;
int Method;

bool fQuit = false;

while (fQuit == false)
{
cout << "(0)Beenden\n";
cout << "(1)Hund\n";
cout << "(2)Katze\n";
cout << "(3)Pferd\n";
cin >> Animal;

switch(Animal)
{
case 0:
fQuit = true;
break;
case 1:
ptr = new Dog;
break;
case 2:
ptr = new Cat;
break;
case 3:
ptr = new Horse;
break;
default:
cout << "\nFalsche Eingabe!\n\n";
continue;
break;
}
if (fQuit == true)
break;

cout << "(1)Sprechen\n";
cout << "(2)Bewegen\n";
cin >> Method;

switch(Method)
{
case 1:
pFunc = Mammal::Speak;
break;
case 2:
pFunc = Mammal::Move;
break;
default:
cout << "\nFalsche Eingabe!\n\n";
continue;
break;
}

(ptr->*pFunc)();
delete ptr;
}

return 0;
}


und die Fehlermeldung des Compilers:

Listing_14_10.cpp: In function `int main()':
Listing_14_10.cpp:86: Fehler: ungültige Verwendung der nicht-statischen Elementf unktion »virtual void Mammal::Speak() const«
Listing_14_10.cpp:86: Fehler: »void (Mammal:: )() const« kann nicht nach »void (M ammal::*)() const« in assignment umgewandelt werden
Listing_14_10.cpp:89: Fehler: ungültige Verwendung der nicht-statischen Elementf unktion »virtual void Mammal::Move() const«
Listing_14_10.cpp:89: Fehler: »void (Mammal:: )() const« kann nicht nach »void (M ammal::*)() const« in assignment umgewandelt werden

Also ich habe das Program soweit verstanden, dass ein Zeiger auf ein Objekt und
ein Zeiger auf eine Methode erzeugt wird.
Der Zeiger auf die Methode wird aber auf die Basisklasse eingerichtet und dann bei
dem jeweiligen Objekt weitergeleitet an die Methode des Objektes.
Vielleicht kann mir das jemand noch besser erklären, was da passiert.:confused:

Danke

locus vivendi
22-11-2005, 12:00
Da findet man wirklich einiges im Netz wo gezeigt wird wie man Pointer-to-member bildet und verwendet. Kleiner Tipp: An zwei Stellen in deinem Snippet ist ein Ampersand ("&") nötig. Noch ein Tipp: Der Compiler hilft dir bereits herauszufinden wo das ist. (Die Fehlermeldung ist sogar äußerst suggestiv!)

RAHUL
22-11-2005, 12:49
Danke für den Tipp und die erste Seite im Netz hat mir auch gleich dieselbe Antwort gegeben.

Allerdings waren ein paar Beispiele zurück, Zeiger auf Funktionen ohne das "&"
und es hat funktioniert. Und das Beispiel jetzt ist auch ohne "&" angegeben.
Da scheint es einen Unterschied zu geben, muss ich mir vielleicht noch mal
genauer im Netz anlesen.;)

peschmae
22-11-2005, 17:16
Zeiger auf "globale" Funktionen gehen ohne &.

Zeiger auf Memberfunktionen benötigen das &. Die sind dann auch mehr wie ein "Offset" oder so, da du die Memberfunktion(spointer) ja nur zusammen mit Angabe eines Objekts verwenden kannst.

MfG Peschmä

RHBaum
24-11-2005, 09:53
Ist die aufgeloeste signatur von methoden eigentlich im standard definiert ?

Normal sollt man unter c++ funktionspointer nur von statischen methoden bilden, bei den anderen ist der aufbau doch compilerabhaengig ?

Im Falle von Rahul waer nach meinem wissensstand sowas eine standard konforme loesung:

class Mammal
{
public:
Mammal():itsAge(1) {}
virtual ~Mammal() {}
virtual void Speak() const = 0;
virtual void Move() const = 0;
static void Speak(const Mammal * pObj){ if(pObj) pObj->Speak(); }
static void Move(const Mammal * pObj){ if(pObj) pObj->Move(); }
protected:
int itsAge;
};

// definition des funktionspointers !
void (pfunk)(const Mammal *) = 0;
// aufruf
pFunc(ptr);

Glaub nich das man so ohne weiteres auf die vtable eines objectes kommt, wenn man standardkonform bleiben will .....

Ciao ...

peschmae
24-11-2005, 17:52
Normal sollt man unter c++ funktionspointer nur von statischen methoden bilden, bei den anderen ist der aufbau doch compilerabhaengig ?


Was genau? Darum verwenden wir ja Memberfunktionspointer! Dann muss man eben keine statischen Methoden machen denen man einen Pointer übergibt, etc

MfG Peschmä

RHBaum
25-11-2005, 10:14
[quote]
Darum verwenden wir ja Memberfunktionspointer!
[quote]

(ptr->*pFunc)();
bin mir nicht sicher ob das ueberall mit jedem compiler funktioniert

was ich nicht verstehe:
pFunc = Mammal::Speak; was soll dir hier geliefert werden ?
Mammal iss ne abstrakte klasse .... Mammal::Speak zeigt auf ne abstrakte funktion ... ne abstrakte funktion existiert nicht, sondern es wird eigentlich nur nen eintrag in der vtable angelegt. die vtable haengt am object. also muesste Dir der compiler was liefern was relativ zur adresse das objects ist ! Tut er das ?
(ptr->*pFunc)(); // und hier tut er genau das gegenteil .... er fuehrt die methode aus, die relativ zu ptr mit abstand von pfunk steht ....
Geht das wirklich so einfach ?


Mal abgesehen das Polymorphie und Funktionspointer miteinander zu verheiraten mir nich sonderlich elegant erscheint, da die eine technik eigentlich nen quasi ersatz der anderen sein sollt ....

Wenns fuer testzwecke ist, ok ^^ im produktiv code wuerd ich fluchen wenn ich ueber sowas stolpere ^^

find grad nix zu im standard, aber muss ja nix heissen, ich such mal weiter ....

Ciao ...

peschmae
25-11-2005, 14:16
(ptr->*pFunc)();
bin mir nicht sicher ob das ueberall mit jedem compiler funktioniert

Achso, das. Das wohl eher ptr->pFunc() heissen.



was ich nicht verstehe:
pFunc = Mammal::Speak; was soll dir hier geliefert werden ?
Mammal iss ne abstrakte klasse .... Mammal::Speak zeigt auf ne abstrakte funktion ... ne abstrakte funktion existiert nicht, sondern es wird eigentlich nur nen eintrag in der vtable angelegt. die vtable haengt am object. also muesste Dir der compiler was liefern was relativ zur adresse das objects ist ! Tut er das ?


Das geht schon. Hab eben mal noch nachgeguckt - das Beispiel im Stroustrup zu dem Thema macht das auch.



Mal abgesehen das Polymorphie und Funktionspointer miteinander zu verheiraten mir nich sonderlich elegant erscheint, da die eine technik eigentlich nen quasi ersatz der anderen sein sollt ....


Da hast du zumindest im konkreten Fall wohl Recht. :D

MfG Peschmä

locus vivendi
25-11-2005, 20:55
(ptr->*pFunc)();
bin mir nicht sicher ob das ueberall mit jedem compiler funktioniert

Achso, das. Das wohl eher ptr->pFunc() heissen.
Das ist schon korrekt so. pFunc war ein "Pointer-to-Memberfunction", und ptr ein Zeiger auf ein Objekt.

bmann
26-11-2005, 00:23
Mal abgesehen das Polymorphie und Funktionspointer miteinander zu verheiraten mir nich sonderlich elegant erscheint, da die eine technik eigentlich nen quasi ersatz der anderen sein sollt ....

Da hast du zumindest im konkreten Fall wohl Recht. :D


Was heisst hier im konkreten Fall? Kannst du mir einen Fall nennen, in denen Zeiger auf Methoden wirklich Sinn machen? Ausser den Code deutlich komplizierter zu machen, meine ich.

Funktionszeiger haben noch eine gewisse Daseinsberechtigung (Callback Funktionen), bei Methoden fällt es da schon schwer zu argumentieren. Zumal eine Callback die nur recht kompliziert zu realisieren ist (wie etwa via Zeiger auf Methoden) wenig Sinn macht (das ist die diplomatische Variante von "gar keinen Seinn").

Zeiger auf Methoden lassen sich praktisch immer durch etwas anderes ersetzen, das
a) einfacher ist (zu lesen, zu implementieren, zu warten, zu debuggen, ...)
b) schneller ist

Wobei der Punkt b) nahezu immer irrelevant ist - allerdings tummeln sich da einige Mythen, dass Methodenzeiger zu benutzen schneller sei als z.B. ein switch da es schliesslich ein Zeiger sei. Das ist allerdings völliger Schwachsinn, da es genau das nämlich im Endeffekt nicht ist.

CU
Andi

peschmae
26-11-2005, 08:08
Das ist schon korrekt so. pFunc war ein "Pointer-to-Memberfunction", und ptr ein Zeiger auf ein Objekt.

Stimmt. Hab da mal wieder was durcheinander gebracht :D


Was heisst hier im konkreten Fall? Das heisst im konkreten Fall.


Kannst du mir einen Fall nennen, in denen Zeiger auf Methoden wirklich Sinn machen? Ausser den Code deutlich komplizierter zu machen, meine ich.


Hey, komm mal runter. Wenn ich dich jetzt zwingen würde Memberfunktionspointer zu verwenden ... - aber das tu ich ja gar nicht.

Kannst du mir beweisen dass es keinen Fall gibt in dem Zeiger auf Methoden Sinn machen?
Ich hab die auch noch nie benutzt darum bring ich auch die Syntax durcheinander. Aber nur weil ich das nicht benutze bzw. nirgends für praktisch Befunden habe heisst das noch lange nicht dass man alle Memberfunktionspointer erwürgen soll...

MfG Peschmä

RHBaum
05-12-2005, 08:58
Ich hab die auch noch nie benutzt darum bring ich auch die Syntax durcheinander. Aber nur weil ich das nicht benutze bzw. nirgends für praktisch Befunden habe heisst das noch lange nicht dass man alle Memberfunktionspointer erwürgen soll...

Naja, vielleicht hat sich bmann nich grad sonderlich diplomatisch ausgedrueckt, aber im Kern hat er doch recht.
Warum was kompliziertes verwenden wenn einfachere Sachen es genau so gut oder besser koennen ?

Zum testen mag es noch angehen, aber im produktiven einsatz machst dir halt keine Freunde mit dieser Experimentierfreudigkeit ^^

Ich weiss im Moment auch nicht wo man sowas wirklich brauchen koennte, und habs auch noch nie gebraucht. Solange lass ich halt dann auch die finger von :-)

Ciao ....