Forum: PC-Programmierung C/C++: Probleme mit Funktionspointern


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Matthias S. (da_user)


Bewertung
-1 lesenswert
nicht lesenswert
Hi,
ich habe da ein Problem beim verwenden von Funktionspointern bei der 
Übergabe bei einer Klasseninitalisierung. Ich habe mich hierbei an den 
zweiten Forenbeitrag in diesem Link gehalten: 
https://www.spieleprogrammierer.de/18-c-cplusplus-csharp-java-und-andere-programmiersprachen/6621-funktionszeiger-funktionen-als-parameter/


Folgendes Szenario:
Ich habe eine Klasse "Class":
1
namespace Namespace
2
{
3
    class Class    
4
    {
5
    private:
6
        void(*FuncPtr)() = NULL;
7
    public:
8
        Class()
9
        {}
10
11
        Class(int value, void(*funcPtr)())
12
        {
13
            FuncPtr = funcPtr;
14
        }
15
    /*****/
16
    };
17
}
Die Funktion wird so definiert und die Klasse so initalisiert:
1
void Funktion()
2
{ /*****/ }
3
4
int foo;
5
6
Namespace::Class Klasse;
7
8
void setup()
9
{
10
    Klasse = Class(foo, void (*Funktion)())  /<<<<Fehler
11
    /****/
12
}
Hier tauchen zwei Fehler auf, einer kommt vom Visual Studio, das 
unterkingelt mir das Rückgabe-void mit dem Fehlertext:
"der Ausdruck vor den Klammern des sichtbaren Aufrufs muss einen 
Funktionstyp (pointer-to-) aufweisen"

Der Compiler meldet mir folgenden Fehler:
"void value not ignored as it ought to be"

Wenn ich die void durch int ersetze, und natürlich für in die Funktion 
ein return 0 einbaue, erhalte ich vom Visual Studio die gleiche 
Fehlermeldung, der Compiler meldet allerdings:
"expression cannot be used as a function".

Was mache ich hier falsch?

von Sven B. (scummos)


Bewertung
4 lesenswert
nicht lesenswert
Nimm std::function, die Syntax ist viel weniger wirr.

von Daniel V. (danvet)


Bewertung
-1 lesenswert
nicht lesenswert
Matthias S. schrieb:

>
1
> void Funktion()
2
> { /*****/ }
3
> 
4
> int foo;
5
> 
6
> Namespace::Class Klasse;
7
> 
8
> void setup()
9
> {
10
>     Klasse = Class(foo, void (*Funktion)())  /<<<<Fehler
11
>     /****/
12
> }

>
> Was mache ich hier falsch?

Reicht es nicht, einfach den Funktionsnamen anzugeben?
1
void setup()
2
{
3
    Klasse = Class(foo, Funktion)
4
    /****/
5
}

von DPA (Gast)


Bewertung
-2 lesenswert
nicht lesenswert
Ungetestet:
1
void Funktion(){}
2
Namespace::Class* Klasse;
3
void setup(){
4
    Klasse = new Class(foo, &Funktion);
5
}

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Bewertung
0 lesenswert
nicht lesenswert
Matthias S. schrieb:

Hallo Matthias,

>         void(*FuncPtr)() = NULL;

diese Art der Initialisierung gibt es erst seit C++11.


>     Klasse = Class(foo, void (*Funktion)())  /<<<<Fehler

Du must hier zwischen der Deklaration eines Parameters von Typen: "Ist 
Funktion, die keine Argumente nimmt und nix zurück gibt" und der 
Übergabe eins konkreten Werts beim Aufruf unterscheiden. Der erst 
Parameter ist von Typen int. Dort übergibst Du doch auch einfach einen 
int:
1
    Klasse = Class(foo, Funktion);

von Matthias S. (da_user)


Bewertung
0 lesenswert
nicht lesenswert
Och man... manchmal sieht man den Baum vor lauter Bäumen nicht. Und wenn 
man sich mit vorherigen Experimenten auch noch selbst eine Falle 
stellt...
Das wars, danke!

: Bearbeitet durch User
von Tom (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wenn man Funktionspointer konsequent weg-typedeft, dann steht die 
ekelhafte Syntax nur an einer Stelle und der Rest des Programms bleibt 
davon verschont:
1
class Class
2
{
3
public:
4
    typedef void (*tVoidFunc)();
5
    Class(int value, tVoidFunc fp) : m_fp(fp) { }
6
private:
7
    tVoidFunc m_fp;
8
};
9
10
void myfunc(){}
11
12
int main(){
13
    Class c(23, myfunc);
14
    return 0;
15
}

von Sven B. (scummos)


Bewertung
1 lesenswert
nicht lesenswert
Wenn man std::function benutzt, braucht man sie nicht mal an einer 
Stelle :D

von nocheinGast (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
Tom schrieb:
> Wenn man Funktionspointer konsequent weg-typedeft [...]

Dafür werden mich jetzt ggf. Leute schimpfen, aber man kann das auch so 
machen:
1
typedef void Funktion();
2
3
void f() {}
4
5
Funktion* fp = f;

von Vincent H. (vinci)


Bewertung
0 lesenswert
nicht lesenswert
Die leserlichste Form einer Typdefinition eines Funktionszeigers bekommt 
man imho via
1
using VoidFp = auto (*)() -> void;

von Sven B. (scummos)


Bewertung
0 lesenswert
nicht lesenswert
using VoidFp = std::function<>;

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
Vincent H. schrieb:
> Die leserlichste Form einer Typdefinition eines Funktionszeigers bekommt
> man imho via
> using VoidFp = auto (*)() -> void;

Ist das ironisch gemein? Da ist ja gegenüber einer normalen 
Funktionsdefinition alles verdreht.

von Vincent H. (vinci)


Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Vincent H. schrieb:
>> Die leserlichste Form einer Typdefinition eines Funktionszeigers bekommt
>> man imho via
>> using VoidFp = auto (*)() -> void;
>
> Ist das ironisch gemein? Da ist ja gegenüber einer normalen
> Funktionsdefinition alles verdreht.

Nein das mein ich ernst. Ich schreib gern C++ Code aber der Purist in 
mir sieht Rückgabewerte lieber am Ende einer Definition.
1
// Go
2
func add(x int, y int) int {
3
  return x + y
4
}
5
6
// Rust
7
fn five() -> i32 {
8
    5
9
}

von Carl D. (jcw2)


Bewertung
0 lesenswert
nicht lesenswert
Vincent H. schrieb:
> Nein das mein ich ernst. Ich schreib gern C++ Code aber der Purist in
> mir sieht Rückgabewerte lieber am Ende einer Definition.
>
>
1
> // Go
2
> func add(x int, y int) int {
3
>   return x + y
4
> }
5
> 
6
> // Rust
7
> fn five() -> i32 {
8
>     5
9
> }
10
>

dann man es doch ;-)
Ist in (modernem) C++ eben eine Form das zu schreiben

von Dr. Sommer (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Matthias S. schrieb:
> Namespace::Class Klasse;
>
> void setup()
> {
>     Klasse = Class(foo, void (*Funktion)())

Dir ist klar, dass du hier erst eine "leere" Instanz anlegst, und dann 
in der main() eine temporäre zweite Instanz, und die über die erste 
kopierst? Einfacher (und effizienter) wäre so:
1
Namespace::Class Klasse (foo, Funktion);
2
int main () {
3
...
4
}
So brauchst du auch den Standard Konstruktor nicht mehr.
Die Instanz einer Klasse nennt man übrigens Objekt, und nicht Klasse...

Matthias S. schrieb:
> void(*FuncPtr)() = NULL;

NULL ist veraltet, bitte nullptr nutzen...

von Matthias S. (da_user)


Bewertung
0 lesenswert
nicht lesenswert
Tom schrieb:
> Wenn man Funktionspointer konsequent weg-typedeft, dann steht die
> ekelhafte Syntax nur an einer Stelle und der Rest des Programms bleibt
> davon verschont:
>
1
> class Class
2
> {
3
> public:
4
>     typedef void (*tVoidFunc)();
5
>     Class(int value, tVoidFunc fp) : m_fp(fp) { }
6
> private:
7
>     tVoidFunc m_fp;
8
> };
9
> 
10
> void myfunc(){}
11
> 
12
> int main(){
13
>     Class c(23, myfunc);
14
>     return 0;
15
> }
16
>

Danke.
Jetzt habe ich verstanden, warum bei der Verwendung von typdef immer von 
"Vereinfachung" gesprochen wird.

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
Matthias S. schrieb:
> Jetzt habe ich verstanden, warum bei der Verwendung von typdef immer von
> "Vereinfachung" gesprochen wird.

Typisches Beispiel dafür ist die Standard-C-Funktion signal():
1
void (*signal(int signum, void (*handler)(int)))(int);

Vereinfacht:
1
     typedef void (*sighandler_t)(int);
2
       sighandler_t signal(int signum, sighandler_t handler);

: Bearbeitet durch User

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.