0

So I just created a struct that makes a rectangle. the struct itself look likes this

    struct _rect
{
    //bottom left vertex
    int x = 0;
    int y = 0;

    // width and height 
    int width = 0;
    int height = 0;

    //top right vertex
    int y2 = y + height;
    int x2 = x + width; 
};

//init rect
_rect rect01;
rect01.x = rect01.y = 50;
rect01.width = rect01.height = 200;

in the main cpp when I want to create an instance of it I just want to enter bottom left x and y, plus width and height and I want it to calculate top right vertex by itself, is there a way to assign x2 and y2 their values without manuly doing so ?

  • 2
    You start with undefined behaviour right with the name of your struct: Names starting with underscore are reserved at global namespace... – Aconcagua Nov 22 '21 at 15:34
  • You might want to read about C++ parametric constructors. – pptaszni Nov 22 '21 at 15:36
  • 1
    can you explain the need of x2,y2 ? rectangle need one point and height and width to be drawn – yassine Nov 22 '21 at 15:37
  • You could have a function calculating `x2` and `y2` and returning their values. You may also find helpful a `Point2D` struct to manage 2D points. – rturrado Nov 22 '21 at 15:37
  • I see, your geometry has the origin at `(0, 0)` in the *bottom left* of the coordinate space, and `x` increases to the right, and `y` increases to the top. Your class needs a *constructor*. The `x2` and `y2` are unnecessary and could be calculated on demand from x,y,width,height as needed, using a getter. – Eljay Nov 22 '21 at 15:40
  • @yassine I need x2 and y2 to render it on screen – Mo_AminKiaee Nov 22 '21 at 15:40
  • 1
    `Constructor` is the keyword here: `struct Rect { Rect(int x, int y, int w, int h) : x(x), y(y), width(w), height(h), y2(y+h), x2(x + w) { } };` – be aware though, that the members are *not* updated automatically if you change one of them – I'd go this way only if you make all of these six values `const` – or if you make them `private` and provide appropriate getters and setters doing the updates for you. Otherwise I'd rather provide `x2` and `y2` as functions doing the necessary calculations on demand. Which one to chose? Depends on the use case, but in most cases rather the functions. – Aconcagua Nov 22 '21 at 15:41
  • 1
    @463035818_is_not_a_number you are right, removed this suggestion – pptaszni Nov 22 '21 at 15:41
  • 1
    @Mo_AminKiaee, The question is, why do you need to _store_ `x2` and `y2`? Why not calculate them on-the-fly? A rectangle is fully specified by four numbers (either x and y and width and height, or x1,y1 and x2,y2.) Storing six numbers is redundant, and it increases the risk of bugs in the program if somebody modifies the code without understanding which part of the code is responsible for ensuring that the six numbers all are consistent with each other. – Solomon Slow Nov 22 '21 at 16:09
  • @SolomonSlow in *veeery* general case one actually need 6 parameters to define arbitrary rectangle, two points and width-height pair (size) can be the set (though in that case some rectangles are rhombus). But in most sample code we think about orthogonal rectangles with sides parallel to the coordinate basis... and rotation angle replaces two extra scalar parameters. For rendering purposes orthogonal rectangle often stored as 6 parameters, or as two corner points, to avoid repeated addition and possible problems related to it. Width\height are rarely used parameters. – Swift - Friday Pie Nov 23 '21 at 08:19
  • @Swift-FridayPie, The 6 values in the OP's case clearly _are_ redundant, since the example shows how two of them are calculated from the other four. A four-valued `Rectangle` object is typical of many graphics libraries in which "rectangle" operations are defined only for rectangles that have horizontal and vertical sides. – Solomon Slow Nov 23 '21 at 14:38
  • @SolomonSlow Contrary, most real-life examples of such class in frameworks I see either do exactly what he did, by taking various combinations of parameters and storing calculated `top, left, right, bottom` as well as `size` as cached result or they use just `top, left, right, bottom`, as that set reduces amount operations and directly is used for rendering. Windows GDI seems to be an exclusion, because there _is_ a function that takes point+size, but it's actually a wrapper around two-point one. – Swift - Friday Pie Nov 24 '21 at 06:20

2 Answers2

3

You should create a specific class:

class Rect
{
public:
  Rect(int x, int y, unsigned int width, unsigned int height)
  : m_x(x), m_y(y), m_width(width), m_height(height)
  {}

  int x() { return m_x; }
  int y() { return m_y; }
  int top() { return m_y + m_height; }
  int right() { return m_x + m_width; }

private:
  int m_x;
  int m_y;
  unsigned int m_width;
  unsigned int m_height;
};

That give you the possibility to do the computation you need in the class methods. You can also create setters and more getters if you want.

BNilsou
  • 886
  • 8
  • 22
  • 5
    prefer initialization over assignment in the constructor body (https://stackoverflow.com/questions/1711990/what-is-this-weird-colon-member-syntax-in-the-constructor) – 463035818_is_not_an_ai Nov 22 '21 at 15:40
  • 1
    Right idea, but use an initializer list in the constructor. `Rect(int x, int y, unsigned width, unsigned height) : x(x), y(y), width(width), height(height) { ... }`. But, of course, real code wouldn't use the same name for the argument and the data member. +1. – Pete Becker Nov 22 '21 at 15:41
  • 3
    Variables and getters need identifiers differing from each other. – Aconcagua Nov 22 '21 at 15:57
1

Below is the complete working example:

#include <iostream>
class Rect
{
public:
  //parameterized constructor 
  Rect(int px, int py, unsigned int pwidth, unsigned int pheight): x(px), y(py), width(pwidth), height(pheight), x2(x + width), y2(y + height)
  {
    
    
   
  };
  
  //getter so that we can get the value of x2 
  int getX2()
  {
      return x2;
  }
  //getter so that we can get the value of y2 
  int getY2()
  {
      return y2;
  }

private:
  int x = 0;
  int y = 0;
  unsigned int width = 0;
  unsigned int height = 0;
  
  int x2 = 0, y2 = 0;
};

int main()
{
    //create Rect instance
    Rect r(50, 50, 200, 200);
    //lets check if x2 and y2 were calculate correctly
    std::cout<<"x2 is: "<< r.getX2()<<std::endl;
    std::cout<<"y2 is: "<< r.getY2()<<std::endl;
}

The output of the above program can be seen here.

Jason
  • 36,170
  • 5
  • 26
  • 60
  • 1
    I suspect that the question wasn't about creating a read-only class. Also, `x2` and `y2` should be initialized in the initializer list. – Pete Becker Nov 22 '21 at 15:50
  • @PeteBecker NO. Read the last sentence in OP's question. He/she writes "I want to create an instance of it I just want to enter bottom left x and y, plus width and height and I want it to calculate top right vertex by itself, is there a way to assign x2 and y2 their values **without manuly doing so** ?" So the OP wants to create the instance and only supply variables `x,y, height, width`. Next he/she wants to automatically calculate the variables `x2, y2`. – Jason Nov 22 '21 at 15:53
  • That's an extraordinarily narrow reading of the question. – Pete Becker Nov 22 '21 at 15:58
  • @PeteBecker That's exactly what the OP want according to the quoted sentence. – Jason Nov 22 '21 at 16:01
  • @Aconcagua Yeah `x2` and `y2` should be initialized using constructor initialized list i agree on this. But note the accepted answer also has a `read only` according to your explanation. – Jason Nov 22 '21 at 16:09
  • @AnoopRana Indeed – but does not claim to be *'complete'* either ;) – Aconcagua Nov 22 '21 at 16:10
  • @Aconcagua By **complete** i meant(and always mean) that you can just copy paste my code and compile it. On the other hand, the accepted answer requires adding things to make it complete(compilable). – Jason Nov 22 '21 at 16:15
  • @Aconcagua Note that i write **complete working example** meaning not a missing `;`(or a typo) but a program with `main()` included which can be executed directly without modifying/adding anything. So by complete i mean **not in parts**. – Jason Nov 22 '21 at 16:26
  • *'example'* – well, ... too little an eye on this word ;) – Aconcagua Nov 22 '21 at 16:38