c++ - 初学者对类和函数有疑问

标签 c++ visual-studio

我是一名初级程序员,在 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() should only be called once, when the program starts -- 仔细阅读该问题的第一个答案。

  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();

...其余代码将继续并正确绘制两个随机初始化的对象。

关于c++ - 初学者对类和函数有疑问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40433843/

相关文章:

c++ - 使用动态变量获取结构的大小?

visual-studio - CanGrow 属性不起作用

c# - VS 设计器中是否有删除事件的方法?

visual-studio - 我想在 4 个工作站上使用 VS 2010 Pro,哪种 MSDN 订阅或许可模式最好?

c++ - 为模板类重载 operator[] - C++

c++ - 将 if-else 替换为 ? : in c++

c++ - 使用带有 OpenSSL API 的私钥生成签名

c++ - 防止非类型模板参数中的类型违规

visual-studio - CMake项目包括更多文件?

visual-studio - 在 Visual Studio 中管理构建版本