Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Tworzenie dziedziczonej klasy figury szachowej

Ostatnio zmodyfikowano 2019-08-21 18:41
Autor Wiadomość
4neta
Temat założony przez niniejszego użytkownika
» 2019-08-13 09:45:20
Tak, to błąd, ponieważ w takim układzie program nie wykonuje swojego zadania (nie ustawia bierki na początkowej pozycji).

Po tych zmianach pojawił się nowy problem. Dziedziczę z klasy bierki "Chessman" klasę pionka "Pawn":
C/C++
class Pawn
    : public Chessman
{
public:
    Pawn( int, int );
};

Pawn::Pawn( int n, int m )
    : Chessman
{
}
Wszystko jest okej do przedostatniej linijki. Podkreśla "Chessman": "No matching constructor for initialization of 'Chessman'".

Konstruktor wygląda tak:
C/C++
Chessman::Chessman( int n, int m )
    : position( n, m )
{
    if( n < 0 || n > 7 || m < 0 || m > 7 ) {
        cout << "Niepoprawne wspolrzedne";
        exit( 0 );
    }
}
Środowisko (Clion) proponuje wykasowanie argumentów "int n, int m" z konstruktora "Chessman". Jednak wtedy kompilator informuje:
In file included from C:\Users\user\CLionProjects\chess\main.cpp:2:
C:/PROGRA~2/MINGW-~1/I686-8~1.0-P/mingw32/i686-w64-mingw32/include/wingdi.h:225:5: error: 'POINT' does not name a type
     POINT ptPosition;
     ^~~~~
A zatem nie mogę tak zrobić.

Nie wiem, czy nie lepiej przynajmniej na początku nauki rozdrobnić się na dwie współrzędne, wtedy rozumiem i działa.

(Przy okazji, jaką komendą należy zmieniać czcionkę na monospace?)
P-175011
pekfos
» 2019-08-13 16:45:07
C/C++
Pawn::Pawn( int n, int m )
    : Chessman
A argumenty? Poprawny zapis masz w tym samym poście co błędny.

(Przy okazji, jaką komendą należy zmieniać czcionkę na monospace?)
Na forum? [tt]. Wszystko jest w » KursyKurs STC kurs
P-175013
4neta
Temat założony przez niniejszego użytkownika
» 2019-08-18 19:36:02
Dziękuję. Czy mogę spytać o coś jeszcze?
Chciałabym, aby klasa szachownicy komunikowała się z klasą pionka w celu pobrania jego lokalizacji. Wiem, że klasy muszą być zaprzyjaźnione, jednak nie wiem w jaki sposób pobrać zmienne jednej klasy z poziomu drugiej klasy. Wywoływanie metody przez poprzedzenie jej nazwą klasy (np. Pawn::getPositionX()) w ogóle nie działa, jakby klasa nie znała tej metody. W jaki sposób mogłabym je powiązać?
(Jeśli kod jest konieczny - wstawię go w późniejszym czasie)
P-175055
pekfos
» 2019-08-18 19:51:44
Wiem, że klasy muszą być zaprzyjaźnione
Co? Nie! Przyjaźń jest po to, by mieć dostęp do całej klasy, a nie tylko jej publicznego interfejsu.

Wywoływanie metody przez poprzedzenie jej nazwą klasy (np. Pawn::getPositionX()) w ogóle nie działa
A skąd program będzie wiedzieć, o który pionek chodzi? Niestatyczne metody wywołuje się na obiekcie, nie na klasie.
P-175056
4neta
Temat założony przez niniejszego użytkownika
» 2019-08-19 11:07:31
Co? Nie! Przyjaźń jest po to, by mieć dostęp do całej klasy, a nie tylko jej publicznego interfejsu.
Być może źle myślę, ale chciałam pobierać współrzędne bierki bezpośrednio ze zmiennych prywatnych klas dziedziczących po Chessman, do tablicy szachownicy klasy Chessboard. (Aby był jakiś obiekt, który trzyma razem układ bierek i później decyduje o możliwych posunięciach dla wszystkich bierek.) Lub użyć tej metody klasy Chessman w klasie Chessboard i analogicznej dla współrzędnej Y:
C/C++
int Chessman::getPositionX() {
    return positionX;
}
Ale rzeczywiście, metoda nie może działać, jeśli nie wskażę jej obiektu. I tu pojawia się moment, którego nie rozumiem. Wydawało mi się, że obiekty tworzę dopiero w funkcji main, aby konkretnie na nich działać. Jak mogę działać na obiekcie w klasie, jeśli tworzę go później? Klasa Chessboard nie widzi klasy Pawn. Problem można rozwiązać łopatologicznie, umieszczając tablicę z bierkami wewnątrz klasy Chessman, ale wolałabym jednak to rozdzielić i przy okazji nauczyć się, w jaki sposób współpracują odrębne klasy.

W razie czego pokażę kod, już bez zaprzyjaźnionych klas:
chessman.h
C/C++
#include <iostream>

using namespace std;

class Chessman
{
private:
    int positionX, positionY;
public:
    Chessman( int, int );
    bool possibleMoves[ 8 ][ 8 ];
    int getPositionX();
    int getPositionY();
    void move( int, int );
};

class Pawn // Pionek dziedziczy po bierce
    : public Chessman
{
public:
    Pawn( int, int );
};

chessman.cpp
C/C++
#include <iostream>
#include "Chessman.h"

using namespace std;

Chessman::Chessman( int n, int m ) { // constructor
    if( 0 <= n && n < 8 && 0 <= m && m < 8 ) {
        positionX = n;
        positionY = m;
    }
    else {
        positionX = 0;
        positionY = 0;
        cout << "You have entered a field outside the chessboard.";
    }
   
    for( int i = 0; i < 7; i++ ) {
        for( int j = 0; j < 7; j++ ) {
            possibleMoves[ i ][ j ] = true;
        }
    }
}

int Chessman::getPositionX() {
    return positionX;
}

int Chessman::getPositionY() {
    return positionY;
}

void Chessman::move( int n, int m ) {
    if( n <= 0 || n > 7 || m <= 0 || m > 7 ) {
        if( possibleMoves[ n ][ m ] ) {
            positionX = n;
            positionY = m;
        }
        else {
            cout << "Incorrect move";
        }
    }
    else {
        cout << "Incorrect value (only 0-7)";
    }
}

Pawn::Pawn( int n, int m ) // constructor without changes
    : Chessman( n, m )
{ }

chessboard.h
C/C++
#include <iostream>

using namespace std;

class Chessboard {
public:
    Chessboard();
    string chessboard[ 8 ][ 8 ];
    void show();
    void loadChessmans();
   
};

chessboard.cpp
C/C++
#include <iostream>
#include "Chessboard.h"

using namespace std;

Chessboard::Chessboard() {
    for( int i = 0; i < 7; i++ ) {
        for( int j = 0; j < 7; j++ ) {
            chessboard[ i ][ j ] = " .";
        }
    }
}

void Chessboard::loadChessmans() {
    // Tutaj chciałabym załadować współrzędne bierek, oznaczając każdą jakimś wybranym znakiem. Następnie tablica possibleMoves[][] będzie wypełniana wartościami true/false wedle zadanych reguł, dla każdej bierki, czyli znowu prześlę dane, z powrotem do klasy dziedziczących po Chessman
}

void Chessboard::show()
{
    for( int j = 0; j < 7; j++ ) {
        for( int i = 0; i < 7; i++ ) {
            cout << chessboard[ i ][ j ];
        }
        cout << endl;
    }
}
(Na początku ograniczam się do konsolki, stąd ten śmieszny sposób pokazywania szachownicy - puste pola to kropki.)

chess.cpp
C/C++
#include <iostream>
#include "Chessman.h"
#include "Chessboard.h"

using namespace std;

int main() {
    Chessboard chessboard;
    chessboard.show();
   
    Pawn wp0( 1, 1 );
    cout << wp0.getPositionY();
    wp0.move( 0, 2 );
    cout << wp0.getPositionY();
    return 0;
}

Dziękuję bardzo za pomoc.
P-175061
pekfos
» 2019-08-19 18:41:20
Jak mogę działać na obiekcie w klasie, jeśli tworzę go później?
Nie możesz wypić herbaty, której jeszcze sobie nie zrobiłaś.

Problem można rozwiązać łopatologicznie, umieszczając tablicę z bierkami wewnątrz klasy Chessman, ale wolałabym jednak to rozdzielić i przy okazji nauczyć się, w jaki sposób współpracują odrębne klasy.
Umieszczać bierki wewnątrz innych bierek? Bez sensu. Umieszczać bierki na szachownicy - znacznie więcej sensu.
C/C++
class Chessboard {
public:
    Chessboard();
    string chessboard[ 8 ][ 8 ];
Czemu by nie tak?
C/C++
class Chessboard {
public:
    Chessboard();
    Chessman * chessboard[ 8 ][ 8 ];
P-175063
4neta
Temat założony przez niniejszego użytkownika
» 2019-08-21 17:59:17
Miałam wcześniej pomysł na stworzenie tablicy z oznaczeniami odpowiadającymi poszczególnym bierkom, bo lepszego sposobu nie znałam.

Chessman * chessboard[ 8 ][ 8 ];
Temat wskaźników również nie jest dla mnie oczywisty. Tworzę wskaźnik na tablicę chessboard typu Chessman. Lecz co dalej i czy wskaźnik jest tu konieczny? Wciąż nie wiem gdzie stworzyć obiekt, realny pionek, na polu np. (0,1). Wydaje mi się, że w main()-ie, ale jak wtedy "wysłać" informacje o lokalizacji do szachownicy?

EDIT: A może inaczej - jak stworzyć metodę, która w sensowny sposób powiąże klasę szachownicy Chessboard i wszystkich klas bierek (dziedziczących po Chessman) tak, że szachownica będzie trzymała lokalizacje bierek, a każda bierka będzie "wiedziała" dokąd może się poruszyć, czyli będzie analizowała układ bierek względem swojego kryterium poruszania się?
P-175073
pekfos
» 2019-08-21 18:32:22
Linia w konstruktorze Chessman * chessboard[ 8 ][ 8 ]; wypełnia tablicę klasami uniwersalnej bierki.
Jeśli piszesz, co myślisz, to myślisz źle. To niczego nie wypełnia. Gdy wcześniej były tam std::string, to czy ta linia w jakiś sposób "wypełniała klasę napisami"? Jakimi napisami? Gdzie podajesz, co mają zawierać? Na pewno nie w tej linii. Klasa jest typem, takim jak int, czy bardziej trafnie jak std::string. Nie możesz niczym "wypełnić" typu zmiennej, najwyżej konkretną zmienną. Ta linia oznacza, że obiekt klasy Chessboard będzie zawierać tablicę wskaźników typu Chessman*. Jeśli nie znasz wskaźników, to najwyższa pora to nadrobić.

Wciąż nie wiem gdzie stworzyć obiekt, realny pionek, na polu np. (0,1). Wydaje mi się, że w main()-ie, ale jak wtedy "wysłać" informacje o lokalizacji do szachownicy?
Gdzie - nie ma żadnego znaczenia, pod warunkiem że nie narobisz bałaganu w kodzie robiąc to w niezręcznym miejscu. Klasa Chessboard jest dobrym kandydatem. W końcu przechowuje pionki.

jak wtedy "wysłać" informacje o lokalizacji do szachownicy
Przekaż jako argument jakiejś metody? Jeśli umiesz używać funkcji i struktur, to programowanie obiektowe to większości tylko make-up na wierzchu tych dwóch. Jeśli nie umiesz, to tu masz wprowadzenie w temat:
» Kurs C++ » Poziom 5Struktury lekcja
Jeśli nie umiesz używać funkcji, to nie wyobrażam sobie jak możesz zabierać się za programowanie obiektowe. Tu jest pierwsza rzecz, której nie da się łatwo uzyskać bez programowania obiektowego i która jest kluczowa do zrozumienia wskaźnika na Chessman:
» Programowanie obiektowe, C++ » PolimorfizmMetody wirtualne lekcja

Tworzę wskaźnik na tablicę chessboard typu Chessman.
Jest w C++ "wskaźnik na tablicę" i jest "tablica wskaźników". To jest tablica wskaźników.

A może inaczej - jak stworzyć metodę, która w sensowny sposób powiąże klasę szachownicy Chessboard i wszystkich klas bierek (dziedziczących po Chessman) tak, że szachownica będzie trzymała lokalizacje bierek, a każda bierka będzie "wiedziała" dokąd może się poruszyć, czyli będzie analizowała układ bierek względem swojego kryterium poruszania się?
Pozycja bierki wynika z tego, gdzie ją wpiszesz w tablicy, więc możesz nawet wyrzucić trzymanie jej wewnątrz bierki. Możesz na przykład zrobić tak, że chcesz wykonać ruch bierką na polu A3 i ruszyć na pole D3. Wywołujesz metodę szachownicy, która sprawdza czy bierka jest na polu A3 i jeśli jest, wywołuje na niej metodę wirtualną sprawdzającą ruch na pole D3, podając też wskaźnik na siebie (this), bierka sprawdza przez wskaźnik na szachownicę, czy ruch jest poprawny. W końcu, niektóre ruchy są poprawne tylko gdy nic nie stoi na drodze, albo gdy celem jest zbicie wrogiej bierki. Jeśli ruch jest poprawny, szachownica przemieszcza bierkę na docelowe pole. Jeśli była tam inna bierka, to zostaje zniszczona.
P-175074
1 « 2 » 3
Poprzednia strona Strona 2 z 3 Następna strona