C++ Funktion in struct ausführen lassen

lemon03

Lieutenant
Registriert
Juli 2004
Beiträge
550
Hallo,

angenommen, ich habe folgende struct:

Code:
struct Calc
{
    int a = 5;
    int b = 10;
    int c = 0;

    void add ( Calc& )
    {
        c = a + b;
    };

};
und folgende main:

Code:
#include "calc.h"
#include <iostream>


int main()
{

    Calc calc;
    calc.add( calc );

    std::cout << "c: " << calc.c << '\n';
}

Ist es möglich, die Funktion add() ausführen zu lassen, ohne das ich sie in der main angeben muss?
 
Auch wenn ich den massiven Verdacht einer Hausaufgabe habe:

C++ Programming Language 4th edition. Teil III, Kapitel 18.
 
Ah so, Stichwort Konstruktor. Komme ich also doch dazu, mich damit und mit Klassen allgemein zu beschäftigen. Habe ich bisher immer vor mir her geschoben.

HominiLupus schrieb:
Auch wenn ich den massiven Verdacht einer Hausaufgabe habe:

Sorry, aber in diesem Fall wirklich Blödsinn. Warum eigentlich? Weil ich mir Mühe gebe, ein einfaches Beispiel zu geben, statt irgendeinen Ausschnitt aus dem tatsächlichen Code?
 
ein weiterer Hinweis sind statische (globale) Variablen, hier insbesondere Klassen-Objekte. Deren Ctor wird bei Programmstart automatisch ausgeführt.
 
Verdammt! Ich bekomme das nicht hin, habe jetzt soviele Varianten versucht, die Klasse auszuschreiben, das ich schon ganz kirre bin. Habe schon versucht, das obige einfach Beispiel zu verkomplizieren, damit das irgend wie mit dem Tutorialbeispiel übereinstimmt, aber bei dieser Vorgehensweise kann ja nichts bei rauskommen.

Und jetzt weiß ich auch wieder, warum ich mich vor Klassen so gesträubt habe.
 
Was hast du denn versucht?
Ergänzung ()

Code:
#include <iostream>

struct Calc
{
    int a = 5;
    int b = 10;
    int c = 0;

    Calc() {
        add();
    }

    void add () {
        c = a + b;
    }
};

int main(int argc, char *argv[])
{
    Calc calc;
    std::cout << "c: " << calc.c << '\n';
}

funktioniert bei mir.
 
Ja, ich habe die Klasse jetzt so ausgeschrieben:

Code:
class Calc
{
public:
    //int c = 0;
    int get_c( int a, int b );
    Calc( int );


private:
    int a = 15;
    int b = 10;

};

Calc::Calc( int )
{
    Calc::get_c( a, b );
}

int Calc::get_c( int a, int b )
{
    int c = a + b;
    return c;
}

Ups, danke, sehe erst jetzt, das Du das Ding korrekt ausgeschrieben hast. Na vielen Dank :) dann werde ich erstmal versuchen, das für meine Zwecke umzuwandeln.
Ergänzung ()

Und Dein Beispiel ist so schön klar und nachvollziehbar. So müsste das dann auch in den Tutorials stehen, damit ich das auch kapiere. Wahrscheinlich steht das für andere auch so da :rolleyes:
 
Vielleicht hilft dir das auch noch:
Code:
#include <iostream>

class Adder
{
public:
    int result = 0;

    Adder(int a, int b) {
        this->a = a;
        this->b = b;

        result = add(a, b);
    }

    int getA() {
        return this->a;
    }

    int getB() {
        return this->b;
    }

    int getResult() {
        return this->result;
    }

    static int add( int a, int b ) {
        return a + b;
    }

private:
    int a = 15;
    int b = 10;
};

int main(int argc, char *argv[])
{
    Adder calc(10, 5);

    std::cout << "1: " << calc.result << std::endl;
    std::cout << "2: " << calc.getResult() << std::endl;
    std::cout << "3: " << Adder::add(10, 30) << std::endl;
}

Hier siehst du unter anderem auch ne statische Methode.
 
Ja danke schön :) Das Stichwort Konstruktor und Deine Beispiele helfen sehr bei meinem aktuellen Code.
 
hier eine andere Variante. Vielfalt kann hilfreich sein ;-)
Code:
#include <iostream>
 

struct Calc
{
    int a = 5;
    int b = 10;
    int c = 0;
 
    void add (Calc& )
    {
        c = a + b;
    };
 
};
 
class Caller {
public:
    Caller():calc() {        
        calc.add(calc);
    }
    
    Calc calc;
};
    
static Caller caller;

int main()
{
       std::cout << "c:" << caller.calc.c << "\n";
}
 
Hallo,

oh danke :)

aber ich habe noch ne grundsätzliche Frage. Ist es sinnvoll, zB in einer Schleife, die gesamte struct/class (mit einer Menge Grundvariablen) über zB setVariable() aufzurufen, oder sollte man lieber solche immer wieder aufzurufende Funktionen aus der struct/class auslagern?

Ersteres wäre deutlich einfacher, aber ist das nicht redundant?
Ergänzung ()

EDIT: ich glaube, Du hast eben unwissentlich eine Antwort auf meine Frage gegeben. Aber glauben heißt eben nicht wissen, in meinem Fall ;)
Ergänzung ()

edit2: ich denke, ich habe da gerade einen Denkfehler, ich rufe ja nicht die gesamte struct auf, sondern nur die enthaltenen Funktionen, oder?

Sorry, bin doch jetzt etwas knülle.

Bis später.
 
Zuletzt bearbeitet:
lemon03 schrieb:
aber ich habe noch ne grundsätzliche Frage. Ist es sinnvoll, zB in einer Schleife, die gesamte struct/class (mit einer Menge Grundvariablen) über zB setVariable() aufzurufen, oder sollte man lieber solche immer wieder aufzurufende Funktionen aus der struct/class auslagern?

Ich weiss nicht so richtig, auf was die Aufgabe hinauslaufen soll, ich vermute aber, es soll ein Funktor gebaut werden:
Code:
...
struct Calc {
    Calc(int xa) : a(xa) {}
    int operator()(int b) const { return a + b; }
private:
    int a;

};

 int main()
{
 Calc calc(5);
 std::cout << "c: " << calc(10) << '\n';
 ...
Kann mich auch irren. Aber die Aufgabe und die bisherige Herangehensweise ist etwas verwirrend ...
 
Zuletzt bearbeitet:
Ja, kann sein. Entweder das, oder ich wusste gestern Abend selbst nicht mehr, was ich da schreibe.
 
Zuletzt bearbeitet:
Hallo. So, mit etwas Abstand... komme ich wohl nicht umhin, auch wegen eines eventuellen XY-Problem, etwas Code zu zeigen, ist aber nicht viel.

Ich habe diese beiden structs:

Code:
struct InitConsole
{

    HANDLE hndl = GetStdHandle( STD_OUTPUT_HANDLE );
    HWND consl = GetConsoleWindow();
    CONSOLE_SCREEN_BUFFER_INFO csbi = {};
    GetDisplay display;                   //Monitorauflösung holen

    int window_size = 0;
    double aspect_x = 4.0, aspect_y = 3.0;
    double aspect_ratio = aspect_x / aspect_y;
    int pos_x = 0, pos_y = 0;
    int columns = 0, rows = 0;
    std::vector <CHAR_INFO> outbuffer;

    InitConsole( int cwindow_size,         //Konstruktor
                 int cpos_x, int cpos_y )
    {
        window_size = cwindow_size;
        pos_x = cpos_x;
        pos_y = cpos_y;
        moveWindow( consl, hndl, csbi, display, window_size, pos_x, pos_y );
    }

    void getCsbi( HANDLE hndl,
                  CONSOLE_SCREEN_BUFFER_INFO csbi )
    {
        GetConsoleScreenBufferInfo( hndl, &csbi );
        columns = csbi.srWindow.Right - csbi.srWindow.Left + 1;
        rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
    };

    void moveWindow( HWND consl,            //Konsolenfenster verschieben
                     HANDLE hndl,
                     CONSOLE_SCREEN_BUFFER_INFO csbi,
                     GetDisplay display,
                     int& window_size,
                     int& pos_x, int& pos_y )
    {
        if ( window_size < static_cast<int> ( (display.height - 22) * aspect_ratio ) ) //wenn window_size einen bestimmten Wert...
        {
            int window_left = static_cast<int> ( (display.width/2 - window_size/2) ) + pos_x;
            int window_top = static_cast<int> ( (display.height/2 - (window_size/aspect_ratio)/2) ) + pos_y;
            int window_right = window_size;
            int window_bottom = static_cast<int> ( window_size/aspect_ratio );
            MoveWindow( consl, window_left, window_top, window_right, window_bottom, TRUE );
            getCsbi( hndl, csbi );
        }
        else //...Konsole wird maximiert
        {
            window_size = display.width;
            pos_x = 0;
            pos_y = 0;
            aspect_x = display.aspect_x;
            aspect_y = display.aspect_y;
            aspect_ratio = aspect_x / aspect_y;
            ShowWindow( consl, SW_MAXIMIZE );
            getCsbi( hndl, csbi );
        }
    };

};

Code:
struct InitDrawing
{

    struct CoordCenter
    {
        int cx = 0;
        int cy = 0;
    } center;

    unsigned int coord_width = 0;
    unsigned int coord_height = 0;

    std::vector <WCHAR> unicodes = { '*', 219 };
    std::vector <WORD> attributes = { 0, 15, 7, 8, 4, 12, 6, 14, 10, 11, 3, 9, 1, 13, 5 };
    std::vector <CHAR_INFO> chars;

    InitConsole console ( int cwindow_size,
                          int cpos_x, int cpos_y );

    InitDrawing( InitConsole& console ) //Konstruktor
    {
        getCoords( console );
        getChars( chars, unicodes, attributes );
        initBuffer( console );
        setTitle( console );
    }

    void getCoords( InitConsole console )
    {
        coord_width = console.columns;
        coord_height = console.rows * 2;
        center.cx = coord_width / 2;
        center.cy = coord_height / 2;
    };

    void getChars( std::vector <CHAR_INFO>& chars,
                   std::vector <WCHAR> unicodes,
                   std::vector <WORD> attributes )
    {
        CHAR_INFO ch;
        for ( auto i : unicodes )
        {
            for ( auto j : attributes )
            {
                ch.Char.UnicodeChar = i;
                ch.Attributes = j;
                chars.push_back( ch );
            }
        }
    };

    void initBuffer( InitConsole& console )
    {
        for ( int i=0; i<console.columns*console.rows; ++i )
        {
            console.outbuffer.push_back( chars.at( 0 ) );
        }

    };

    void setTitle( InitConsole console )
    {
        std::stringstream sstr;
        sstr << "  columns: " << console.columns << "  rows: " << console.rows;
        sstr << "  coord_width: " << coord_width << "  coord_height: " << coord_height;
        sstr << "  center.cx: " << center.cx << "  center.cy: " << center.cy;
        SetConsoleTitle( TEXT( sstr.str().c_str() ) );
    };

};

Diese werden in der main so aufgerufen:

Code:
    int cwindow_size = 1200; //Größe und
    int cpos_x = 0;          //Position Konsolenfenster
    int cpos_y = 0;
    InitConsole console( cwindow_size, cpos_x, cpos_y );
    InitDrawing drawing( console );

Bei einem einmaligen Aufruf mag das wohl ok sein, allerdings will ich diese in eine Funktion auslagern und bei Bedarf mehrmals aufrufen. Aber erstens weiß ich nicht wie und zweitens werden bei jedem Aufruf die structs neu initialisiert (?), und das kann doch nicht richtig sein?

Deshalb meine obige Frage, ob ich dies irgendwie über Konstruktoren lösen kann, oder ob ich nicht dann doch die entsprechenden Funktionen aus der struct rausnehme?

edit: in moveWindow() gibt es eine komische Verschiebung, die war in der Vorschau nicht zu sehen?
 
Zuletzt bearbeitet:
Hier würde sich wohl eine Klasse im Stile wie in .Net die "Console" anbieten.

Da hast du dann statische Methoden wie bspw. "setTitle()", "setSize()", "setCursorPosition()".

Deine Namen "InitConsole" und "InitDrawing" finde ich übrigens eigenartig. Wofür soll das stehen? Das Initialisieren der Konsole?
Das macht man entweder im Konstruktor der Klasse "Console" oder in einer extra Methode "init()". Du aber nutzt Klassen als Methoden.
 
Zuletzt bearbeitet:
Aha. Das 'Init' sollte darauf hinweisen, das dort alle grundlegenden Variablen für das weitere Programm gesetzt werden. Aber wenn das keine gute Idee ist, werde ich das lieber ändern.

Methoden nennt man doch Funktionen innerhalb einer Klasse, oder? Kannst Du das näher erläutern, wie ich Klassen als Methoden nutze?
Ergänzung ()

Ich habe jetzt mal kurz nach statische Methoden geschaut und das erste Beispiel kam wieder mit einer Klasse Tier. Ich kann damit nichts anfangen. Kann man nicht mal zB eine Klasse Dreieck zeigen oder sonst was in der Richtung, was nachvollziehbar ist?
 
Du kannst dich bspw. fragen, ob deine Methode "setTitle" nur zum initialisieren verwendet werden kann. Falls nicht, dann macht es sinn, sie wo anders hinzustecken. *hust* "Console::setTitle(foo)"


Wie du Klassen als Methoden nutzt? Nun ja. Du willst deine Programm initialisieren, also erstellst du die Klasse InitConsole - wie als wäre es eine Methode. Sinnvoller wäre aber "Console.init()", oder alternativ (falls es Sinn ergibt), das ganze statisch: "Console::init()".
 
Aha, ja stimmt eigentlich. Ich glaub ich werd die Dinger noch mal ganz neu aufsetzen. setTitle() zB kann ja erst ausgeführt werden, wenn die obige InitDrawing (diese Bezeichnung nehme ich natürlich nicht mehr) durchgelaufen ist.

Und danke für den zweiten Vorschlag, muss mich in die statischen noch etwas einarbeiten.
 
Zuletzt bearbeitet:
Zurück
Oben