Selamat pagi. Saya belajar beberapa konsep tentang manipulasi warisan dan konsol. Saya cukup pemula seperti yang Anda lihat.

Jadi saya mencoba memiliki satu karakter yang ditarik pada konsol dan saya ingin posisinya diperbarui. Sekarang harap dicatat bahwa saya tahu kode saya mungkin sangat buruk dalam berbagai cara dan mungkin ada ratusan cara alternatif yang lebih baik untuk melakukan ini, tetapi saya ingin memahami beberapa konsep warisan terlebih dahulu dan mengapa itu tidak berfungsi seperti itu.

Jadi, saya menggambar karakter pemain saya "x" di konsol, maka saya memperbarui posisinya memanggil metode anggota tertentu untuk memindahkannya. Sekarang, karena saya membuatnya bahwa kelas pemain memperluas kelas Drawconsole, saya ingin memanggil drawconsole pada instance pemain.

Ketika saya melakukan ini, saya memiliki instance Playera yang memiliki koordinat posisinya benar-benar diperbarui, tetapi referensi ke instance pemain sekarang memiliki dua anggota yang disebut 'posisi', seperti yang Anda lihat pada gambar. Bagaimana saya bisa mengatakan untuk memilih Playera One tanpa sepenuhnya membuat ulang kode atau menggunakan pendekatan yang sama sekali berbeda? Atau mungkin hanya saya tidak bisa dan saya benar-benar menyelesaikan perubahan pendekatan? Semoga saya bisa mengkomunikasikan apa yang diragukan saya sebenarnya.

Ini kodenya

#include <ctime>
#include <cstdlib>
#include "windows.h"

#define width 100
#define height 15

class StaticBuffer
{
public:
    StaticBuffer() { srand(time(0)); }

    void loadBackGround(CHAR_INFO *backGround, int swidth, int sheight)
    {

        for (int y = 0; y < sheight; y++)
        {
            int rnd = rand() % 100 + 1;
            for (int x = 0; x < swidth; x++)

                if (y == 0 || y == sheight - 1)
                {
                    backGround[y * swidth + x].Char.AsciiChar = (unsigned char)127;
                    backGround[y * swidth + x].Attributes = (unsigned char)23;
                }
                else if (x > 4 * rnd && x < (4 * rnd) + 5 || x > 4 * rnd / 2 && x < (4 * rnd / 2) + 5)
                {
                    backGround[y * swidth + x].Char.AsciiChar = (unsigned char)178;
                    backGround[y * swidth + x].Attributes = (unsigned char)12;
                }
                else
                {
                    backGround[y * swidth + x].Char.AsciiChar = 32;
                    backGround[y * swidth + x].Attributes = (unsigned char)3;
                }
        }

    }

private:
};

class DrawConsole
{
public:
    DrawConsole()
    {
        wConsole = GetStdHandle(STD_OUTPUT_HANDLE);
        rConsole = GetStdHandle(STD_INPUT_HANDLE);
        windowSizeInit = {0, 0, 30, 10};
        windowSize = {0, 0, bufferSize.X - 1, bufferSize.Y - 1};
        backGround = new CHAR_INFO[bufferSize.X * bufferSize.Y];
        obstacle = new CHAR_INFO[bufferSize.X * bufferSize.Y];
        inputBuffer = new INPUT_RECORD[4];
        drawBackGround.loadBackGround(backGround, bufferSize.X, bufferSize.Y);
        nInputWritten = 0;
        nOutputWritten = 0;
        playerString[0] = L'X';
        charLenght = 1;
        position = {10,13};
    }

    void drawConsole()
    {
        wConsole = GetStdHandle(STD_OUTPUT_HANDLE);
        rConsole = GetStdHandle(STD_INPUT_HANDLE);

        SetConsoleWindowInfo(wConsole, TRUE, &windowSizeInit);
        wConsole = GetStdHandle(STD_OUTPUT_HANDLE);

        SetConsoleScreenBufferSize(wConsole, bufferSize);
        SetConsoleWindowInfo(wConsole, TRUE, &windowSize);

        WriteConsoleOutputA(wConsole, backGround, bufferSize, {0,0}, &windowSize);
        WriteConsoleOutputCharacterW(wConsole, playerString, charLenght, position, &nOutputWritten);
    }

    void drawChar()
    {
        WriteConsoleOutputA(wConsole, backGround, bufferSize, {0,0}, &windowSize);
        WriteConsoleOutputCharacterW(wConsole, playerString, charLenght, position, &nOutputWritten);
    }


protected:
    HANDLE wConsole;
    HANDLE rConsole;

    COORD bufferSize{width, height};
    SMALL_RECT windowSizeInit;
    SMALL_RECT windowSize;

    CHAR_INFO *backGround;
    CHAR_INFO *obstacle;

    INPUT_RECORD *inputBuffer;
    DWORD nInputWritten;
    DWORD nOutputWritten;
    DWORD charLenght;

    StaticBuffer drawBackGround;
    wchar_t playerString[2];


    COORD position;
};

class Player :public DrawConsole
{
public:
    Player()
    {
        position.X = 20;
        position.Y = height - 2;
    }

    void movePlayerRight()
    {
        for (int i = 0; i < 3; i++)
            position.X += 1;
    }
    COORD getPositionC() { return position; }

private:

    COORD position;
};
Player *playerA = new Player;
DrawConsole *myConsole = new DrawConsole;

int main()
{
    myConsole->drawConsole();
    while (true)
    {
        //Sleep(5000);
        playerA->movePlayerRight();
        playerA->drawChar();
    }
} 

image

0
MILO 5 April 2021, 12:48

1 menjawab

Jawaban Terbaik

Itu tergantung pada apa yang sebenarnya Anda inginkan. Jika idenya adalah bahwa kedua variabel mewakili konsep yang sama, Anda seharusnya tidak mendefinisikan kembali di kelas turunan, karena "dilindungi" di kelas dasar sehingga kelas yang diturunkan mampu mengaksesnya.

Jika variabel mewakili hal-hal yang berbeda, tetapi mereka memiliki nama yang sama (yang, omong-omong, akan menjadi ide yang buruk), Anda dapat memenuhi syarat dengan kelas variabel telah didefinisikan dalam. Jadi, misalnya, Anda bisa melakukannya melakukan:

DrawConsole::position.X += 1;

Untuk memodifikasi variabel position dinyatakan dalam DrawConsole dan:

Player::position.X += 1;

Untuk memodifikasi variabel position dinyatakan dalam Player

Tapi, seperti yang saya katakan sebelumnya, saya akan berusaha menghindari dua variabel dengan nama yang sama karena dapat dengan mudah mengakibatkan kesalahan.


UPDATE:

Jika Anda ingin mempertahankan warisan seperti itu, cukup hapus atribut position dari Player. Alasannya adalah sebagai berikut:

Saat ini, ketika Anda menelepon drawChar, Anda sedang mengeksekusi kode yang ada di kelas DrawConsole (Player sendiri tidak menentukan metode drawChar). Kode ini tidak dapat mengakses Player::position karena suatu metode di kelas induk tidak dapat mengakses atribut di kelas anak (bahkan jika Anda menelepon metode dari instance kelas anak), sehingga hanya melihat DrawConsole::position Dan itu adalah variabel yang digunakan.

Tetapi ketika Anda menelepon movePlayerRigth dalam instance Player, kode yang sedang dieksekusi adalah metode di kelas Player. Metode ini mencoba mengakses atribut posisi dan mengetahui bahwa ada dua kemungkinan: DrawConsole::position dan Player::position. Dalam hal ini, ia memilih Player::position karena didefinisikan di kelas yang sama.

Jadi, Anda memiliki metode yang menggambar konsol berdasarkan DrawConsole::position dan metode lain yang memodifikasi Player::position. Ini tidak dapat bekerja dan pada kenyataannya jika Anda menjalankannya, Anda akan melihat bahwa X tidak bergerak.

Jika Anda menghapus variabel position dari Player, di movePlayerRight ketika Anda mencoba mengakses variabel position, kode akan melihat bahwa Player tidak mendefinisikan a Atribut posisi, tetapi menyadari bahwa kelas induknya (DrawConsole) memang mendefinisikan atribut position, dan dengan akses yang dilindungi. Dilindungi berarti kode pada kelas anak dapat mengaksesnya secara langsung, dan begitu movePlayerRight akan memodifikasi DrawConsole::position. Dalam hal ini, keduanya drawChar dan {{x10}} akan mengakses variabel yang sama dan itu akan berfungsi seperti yang diharapkan.

Jadi, jika Anda menginginkannya dengan cara ini, hapus dari kelas pemain baris:

COORD position;

Dan Anda akan melihat bahwa kode ini mengkompilasi dan berfungsi seperti yang diharapkan (X bergerak kanan) karena sekarang kode dalam Player dan kode di DrawConsole mengakses variabel yang sama (DrawConsole::position) .

2
Ion Larrañaga 5 April 2021, 15:17