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


von Matthias S. (da_user)


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)


Lesenswert?

Nimm std::function, die Syntax ist viel weniger wirr.

von Daniel V. (danvet)


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)


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)


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)


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)


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)


Lesenswert?

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

von nocheinGast (Gast)


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)


Lesenswert?

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

von Sven B. (scummos)


Lesenswert?

using VoidFp = std::function<>;

von Rolf M. (rmagnus)


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)


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)


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)


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)


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)


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
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.