初学者对类和函数有问题

Beginner having an issue with classes and functions

本文关键字:函数 有问题 初学者      更新时间:2023-10-16

我是一个初学者程序员,在c++ visual studio 2015中开发一个程序,该程序需要一个名为rect的类的实例,并将其传递给rect中的一个函数,该函数在控制台窗口的想象板上设置一个随机大小和位置的矩形。在代码的底部有关于代码需要做什么的完整说明。我遇到的问题是,当程序打印矩形时,"0"的矩形不打印,但"1"的矩形打印。矩形rect0是通过引用传递的,rect1是通过指针传递的。

/*
iLab2: rectangles
*/
#define NOMINMAX // prevent Windows API from conflicting with "min" and "max"
#include <stdio.h>   // C-style output. printf(char*,...), putchar(int)
#include <windows.h> // SetConsoleCursorPosition(HANDLE,COORD)
#include <conio.h>   // _getch()
#include <time.h>
/**
* moves the console cursor to the given x/y coordinate
* 0, 0 is the upper-left hand coordinate. Standard consoles are 80x24.
* @param x
* @param y
*/
void moveCursor(int x, int y)
{
    COORD c = { x,y };
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);
}
struct Vec2
{
    short x, y;     // variables x and y for storing rectangle coordinates
    Vec2() : x(0), y(0) { }     // default constructor for vect2 if no parameters are specified
    Vec2(int x, int y) : x(x), y(y) { } // default constructor for vect2 if parameters are given
    void operator+=(Vec2 v)     // function for adding or subtracting (if v is negative) to move the rectangle
    {
        x += v.x;
        y += v.y;
    }
};
class Rect
{
    Vec2 min, max;
public:
    Rect(int minx, int miny, int maxx, int maxy)
        :min(minx, miny), max(maxx, maxy)
    {}
    Rect() {}
    void draw(const char letter) const
    {
        for (int row = min.y; row < max.y; row++)
        {
            for (int col = min.x; col < max.x; col++)
            {
                if (row >= 0 && col >= 0)
                {
                    moveCursor(col, row);
                    putchar(letter);
                }
            }
        }
    }
    void setMax(int maxx, int maxy)
    {
        this->max.x = maxx;
        this->max.y = maxy;
    }
    void setMin(int minx, int miny)
    {
        this->min.x = minx;
        this->min.y = miny;
    }
    bool isOverlapping(Rect const & r) const
    {
        return !(min.x >= r.max.x || max.x <= r.min.x
            || min.y >= r.max.y || max.y <= r.min.y);
    }
    void translate(Vec2 const & delta)
    {
        min+=(delta);
        max+=(delta);
    }
    void setRandom(Rect & r);
    void setRandom(Rect* r);
};

void Rect::setRandom(Rect & r)
{
    srand(time(NULL));      // added to make the random placement and size of the rect different each time program runs
    int pos_x, pos_y, height, width;
    pos_x = rand() % 51;
    pos_y = rand() % 21;
    height = 2 + rand() % 11;
    width = 2 + rand() % 11;
    height = height / 2;
    width = width / 2;
    r.min.x = pos_x - width;
    r.min.y = pos_y - height;
    r.max.x = pos_x + width;
    r.max.y = pos_y + height;
}
void Rect::setRandom(Rect * r)
{
    srand(time(NULL));      // added to make the random placement and size of the rect different each time program runs
    int posX, posY, heightPoint, widthPoint;
    posX = rand() % 51;
    posY = rand() % 21;
    heightPoint = 2 + rand() % 11;
    widthPoint = 2 + rand() % 11;
    heightPoint = heightPoint / 2;
    widthPoint = widthPoint / 2;
    this->min.x = posX - widthPoint;
    this->min.y = posY - heightPoint;
    this->max.x = posX + widthPoint;
    this->max.y = posY + heightPoint;
}
int main()
{
    // initialization
    //Rect userRect(7, 5, 10, 9);       // (x-min, y-min, x-max, y-max) x-min how far left the rectange can be
    //Rect rect0(10, 2, 14, 4);     // (x-min, y-min, x-max, y-max)
    //Rect rect1(1, 6, 5, 15);      // (x-min, y-min, x-max, y-max)
    //Rect userRect;
    Rect * userRect;
    Rect rect0;
    Rect rect1;
    const int rectSize = 5;
    Rect rect[rectSize];

    userRect = new Rect();
    // set
    rect[0].setRandom(rect[0]);
    rect[1].setRandom(& rect[1]);
    userRect->setMin(7, 5);
    userRect->setMax(10, 9);
    //rect0.setMin(10, 2);
    //rect0.setMax(14, 4);
    //rect1.setMin(1, 6);
    //rect1.setMax(5, 15);
    int userInput;
    do
    {
        // draw
        rect[0].draw('0');  // drawing the 0 rectangle with an x width of 4 and a y height of 2
        rect[1].draw('1');  // drawing the 1 rectangle with a x width of 4 and a y height of 9
        moveCursor(0, 0);   // re-print instructions
        printf("move with 'w', 'a', 's', and 'd'");
        userRect->draw('#');    // drawing the user rectangle in its starting location with a x width of 3 and a y height of 4
        // user input
        userInput = _getch();
        // update
        Vec2 move;
        switch (userInput)
        {
        case 'w':   move = Vec2(0, -1); break;      // Moves the user Rectangle -y or up on the screen
        case 'a':   move = Vec2(-1, 0); break;      // Moves the user Rectangle -x or left on the screen
        case 's':   move = Vec2(0, +1); break;      // Moves the user Rectangle +y or down on the screen
        case 'd':   move = Vec2(+1, 0); break;      // Moves the user Rectangle +x or right on the screen
        }
        userRect->draw(' ');    // un-draw before moving
        userRect->translate(move);      // moves the user rectangle to the new location
    } while (userInput != 27); // escape key
    delete userRect;    // delete dynamic object to release memory
    return 0;
}
// INSTRUCTIONS
// ------------
// 3) Random rectangles, by reference and by pointer
//   a) create a method with the method signature "void setRandom(Rect & r)".
//      This function will give the passed-in Rect object a random location.
//      The random x should be between 0 and 50 x. The random y should be  
//      between 0 and 20. Limit the possible width and height to a minimum of 2
//      and a maximum of 10.
//   b) test "void setRandom(Rect & r)" on the local Rect object "rect0".
//   c) create a method with the method signature
//      "void setRandomByPointer(Rect * r)", which functions the same as
//      "void setRandom(Rect & r)", except that the argument is
//      passed-by-pointer.
//   d) test "void setRandomByPointer(Rect * r)" on the local Rect object
//      "rect1".
// 4) Test and show overlap
//   a) Using the existing function "isOverlapping(Rect const &)", test to see
//      if userRect collides with any other Rect objects. If userRect is
//      overlapping, draw it with '+' instead '#'.
//   b) Create a Rect * pointer that points to the address if the Rect object
//      that userRect collides with. It should point at NULL if userRect is
//      colliding with no other Rect objects.
//   c) Print to the screen the width and height of a Rect object that userRect
//      collides with. If no collision is happening, print "no collision"
//      instead.
// 5) Array of objects
//   a) Replace the Rect objects rect0 and rect1 with an array of 2 Rect
//      objects, "rect[2]".
//   b) Make sure you replace every remaining "rect0" with "rect[0]", and every
//      "rect1" with "rect[1]".
//   c) Increase the size of the "rect" array to 5. Make sure all 5 Rect
//      objects are randomized, drawn to the screen, and tested for collision.
//   d) If you have not already done so, replace
//      duplicate-code-using-array-elements with a for-loop. For example:
//      If you have:
//          rect[0].draw('0');
//          rect[1].draw('1');
//          rect[2].draw('2');
//          rect[3].draw('3');
//          rect[4].draw('4');
//      Replace it with:
//          for(int i = 0; i < NUMBER_OF_RECTS; i++)
//          {
//              rect[i].draw('0'+i);
//          }
//      Do this where objects are randomized, drawn, and tested for collision

你有两个不同的setRandom()方法,有三个问题。

  1. 每次setRandom()被调用时,srand()也被调用。srand()应该只被调用一次,当程序启动时——仔细阅读这个问题的第一个答案。

  2. 代码重复。两个setRandom()中的代码几乎相同。代码重复是不好的。重复的代码意味着,如果需要以某种方式更改算法,您将不得不记住在两个地方进行修改。或者三个地方。或者四个位置。或者代码中存在多少重复的代码块。你必须记住它们,然后找到它们。

  3. 与#2相同的问题,但对于"几乎相同"的部分。不同之处在于:setRandom()的第一个版本接受对另一个对象的引用,并修改通过引用传递的另一个对象。第二个版本的setRandom()接受指向另一个对象的指针,而不是引用,但完全忽略它,并初始化this,而不是指向的对象。

并且,由于这些错误,我们得到了您所看到的结果。

rect[0].setRandom(rect0);

这将初始化rect0rect[0]被完全忽略,根本不初始化。

rect[1].setRandom(& rect1);

这将初始化rect[1]rect1被完全忽略,根本不初始化。

这就是为什么代码的其余部分无法绘制rect[0]。它根本不初始化。

显示的代码完全令人困惑,因为它有四个而不是两个对象。rect0、rect1和包含另外两个对象的rect[]数组。在声明rect0和rect1之后,它们将被完全忽略,除了初始化失败之外,它们显然没有任何用途。

这里也没有任何真正的理由让setRandom()接受指针或对其他对象的引用。setRandom()的明显目的是随机初始化对象的尺寸。

所以它应该简单地随机初始化this的维度。通过指针或引用传递其他对象根本没有意义。

然后,在去掉rect0rect1之后,简单地调用单个setRandom()方法…

rect[0].setRandom();
rect[1].setRandom();

…剩下的代码将继续并正确地绘制两个随机初始化的对象。

代码Rect rect[ rectSize ]将创建5个矩形到数组rect,所有这些矩形都是min(0,0) max(0,0)(初始状态)。当你调用rect[ 0 ].setRandom( rect0 )时,它将更新rect0(你通过引用传递它),而对rect[0]不做任何事情。当你调用rect[ 1 ].setRandom( &rect1 )时,你更新rect[1](通过this->min)。x = posX -某个值)。所以你得到了rect[0]和rect[1]的差值