struct having another struct

Stuck with structs...
Trying to do something like this:

struct Point
{
  uint8_t X;
  uint8_t Y;
  Point(uint8_t _x, uint8_t _y) 
    {
    X=_x; 
    Y=_y;
    }
};

struct Rectangle
{
  Point LeftBottom;
  uint8_t Width;  
  uint8_t Height; 
  Rectangle(Point _leftbottom, uint8_t _width, uint8_t _height) 
    { //<<< ---- error "no matching function for call to 'Point::Point()' is here
      LeftBottom=_leftbottom; 
      Width=_width; 
      Height=_height;
    }
};

Got error "no matching function for call to 'Point::Point()' on Rectangle constructor.
What am i doing wrong?

You need to use an initializer list for 'Point LeftBottom' within Rectangle. See #3 here: When do we use Initializer List in C++? - GeeksforGeeks

Or add back the default constructor.

struct Point
{
  uint8_t X;
  uint8_t Y;
  Point()
   {
   X = Y = 0;
   }
  Point(uint8_t _x, uint8_t _y)
    {
    X=_x;
    Y=_y;
    }
};

the language excepts your paramiters as a function like youve written as long as you are not declaring the class. Not sure why. Anyways if you declaire the structs ahead of time it prevents your error. I guess this makes the two structs ready for each other.

void loop() {
  // put your main code here, to run repeatedly:

}
struct Rectangle;
struct Point;

struct Point
{
  uint8_t X;
  uint8_t Y;
  Point(uint8_t _x, uint8_t _y)
    {
    X=_x;
    Y=_y;
    }
};

struct Rectangle
{
  Point LeftBottom;
  uint8_t Width; 
  uint8_t Height;
  void Rectange(Point _leftbottom, uint8_t _width, uint8_t _height)
    { //<<< ---- error "no matching function for call to 'Point::Point()' is here
      LeftBottom=_leftbottom;
      Width=_width;
      Height=_height;
    }
};

taterking:
the language excepts your paramiters as a function like youve written as long as you are not declaring the class. Not sure why. Anyways if you declaire the structs ahead of time it prevents your error. I guess this makes the two structs ready for each other.

void loop() {

// put your main code here, to run repeatedly:

}
struct Rectangle;
struct Point;

struct Point
{
  uint8_t X;
  uint8_t Y;
  Point(uint8_t _x, uint8_t _y)
    {
    X=_x;
    Y=_y;
    }
};

struct Rectangle
{
  Point LeftBottom;
  uint8_t Width;
  uint8_t Height;
  void Rectange(Point _leftbottom, uint8_t _width, uint8_t _height)
    { //<<< ---- error "no matching function for call to 'Point::Point()' is here
      LeftBottom=_leftbottom;
      Width=_width;
      Height=_height;
    }
};

I don't know what that does, but I'm pretty sure it's not right. Adding 'void' in front of 'Rectange(...' defines some kind of function, not a constructor as the OP intended.

BTW, in C++, structs and classes are essentially the same thing.

I am very curious to know why the OP has included functions in the data structure created by struct keyword; whereas, functions are usually included in a data structure called Class created using class keyword.

GolamMostafa:
I am very curious to know why the OP has included functions in the data structure created by struct keyword; whereas, functions are usually included in a data structure called Class created using class keyword.

AFAIK the only difference between "struct" and "class" is that by default member fields are public in a struct whereas they are private in a class - other that that they are treated identically by the compiler.

GolamMostafa:
I am very curious to know why the OP has included functions in the data structure created by struct keyword; whereas, functions are usually included in a data structure called Class created using class keyword.

There's nothing wrong with adding methods to structs. Structs and classes are equivalent in C++ (except for the default access specifiers).
Classes are generally used when the data structure has an invariant (this is usually closely related to having private attributes), and structs are used when there's no invariant, meaning the user can set the attributes to any value without breaking anything.

Points and rectangles usually don't have invariants, so I agree with OP that struct is the right choice.

This is just a convention, of course.

Pieter

PieterP:
This is just a convention, of course.

I must welcome with + for the satisfactory explanation.

Now, to deal with the problem of OP --

OP's codes are:

struct Point
{
  uint8_t X;
  uint8_t Y;
  Point(uint8_t _x, uint8_t _y)
    {
    X=_x;
    Y=_y;
    }
};

struct Rectangle
{
  Point LeftBottom;
  uint8_t Width; 
  uint8_t Height;
  Rectangle(Point _leftbottom, uint8_t _width, uint8_t _height)
    { //<<< ---- error "no matching function for call to 'Point::Point()' is here
      LeftBottom=_leftbottom;
      Width=_width;
      Height=_height;
    }
};

In Rectangle Structure, he has these thee variables (from programming point of view): LeftBottom, Width, and Height. He wants to initialize them with this parametrized constructor: Rectangle(x, y, z) which is logically correct; but, it is not compiled.

He is getting this error: no matching function for call to 'Point::Point()'. Can it be corrected? How? If not, why not?

There are two possible solutions:

  1. Add a default constructor to Point.
    When you provide your own constructor, the compiler implicitly deletes the default constructor. You can add it yourself:
struct Point {
  uint8_t x = 0; // member variable x with default value of 0
  uint8_t y = 0;
  Point(uint8_t x, uint8_t y)
   : x(x), y(y) {} // members x and y are initialized with parameters x and y
  Point() = default; // x and y are not explicitly initialized → defaults are used
};

When the values of x and y are not specified in the initializer list (see below), the default value is used (0 in this case).

  1. Use an initializer list in Rectangle::Rectangle.
    When an object is constructed, all of its member objects are constructed first. This happens before the body of the constructor is executed.
    The compiler can't construct the LeftBottom member because no arguments are passed to its constructor, and the default constructor of Point is deleted. The fact that a new value is assigned to leftbottom in the body of the constructor is irrelevant at this stage, all member objects must be constructed/initialized before it gets to the body.

The solution is to use an initializer list, this way, you can pass arguments to the Point constructor. This initialization happens before the body of the constructor is executed.
It's best practice to use list initialization for all members, this prevents bugs with the order of initialization, and you can use the same names for the parameters as for the members.

struct Rectangle {
  Point leftbottom;
  uint8_t width; 
  uint8_t height;
  Rectangle(Point leftbottom, uint8_t width, uint8_t height)
   : leftbottom(leftbottom), width(width), height(height) {}
};

GolamMostafa:
He is getting this error: no matching function for call to 'Point::Point()'. Can it be corrected? How? If not, why not?

See Replies #1 and #2 which @PieterP consolidated into Reply #9. It's good practice to read all the replies before posting.

gfvalvo:
See Replies #1 and #2 which @PieterP consolidated into Reply #9. It's good practice to read all the replies before posting.

Not all posts are equally intelligible; it depends on the poster how much descriptive he is along with his codes, and it also depends on the reader how much academic/practitioner he is on the current topics.

PieterP:
There are two possible solutions:

Based on your directives of Post#9, the OP's codes are now compiled without error; however, there are few queries/questions that follow:

struct Point
{
  uint8_t X = 0;
  uint8_t Y = 0;
  Point(uint8_t _x, uint8_t _y): X(_x), Y(_y) {}
  Point() = default;
};

struct Rectangle
{
  Point LeftBottom;
  uint8_t Width;
  uint8_t Height;
  Rectangle(Point _leftbottom, uint8_t _width, uint8_t _height)
    : LeftBottom(2, 3), Width(4), Height(6) {}
};

Point myDimension(12, 3);

void setup()
{
  Serial.begin(9600);
  Serial.println(myDimension.X);  //shows: 12
}

void loop()
{

}

Queries/Questions:
1. I have given values for the arguments/parameters of the initializer list of Rectangle Structure like these:

Rectangle(Point _leftbottom, uint8_t _width, uint8_t _height)
    : LeftBottom(2, 3), Width(4), Height(6) {}

(1) How do I create an object using the Rectangle Structure? (something like: Rectangle recta((x,y), u, v):wink:

(2) Once, the object is created; how do I print 2 (the value that has been assigned to X of LeftBottom object which is an instance of Point Structure?

(3) Once, the object is created; how do I print 4 (the value that has been assigned to Width of recta object which is an instance of Rectangle Structure?

2. It looks like that the following two blocks of codes of the Rectangle() constructor are not equivalent. Why not? (Sketch with the top constructor function gets compiled, and the bottom one gives error.)

Rectangle(Point _leftbottom, uint8_t _width, uint8_t _height)
    : LeftBottom(_leftbottom), Width(_width), Height(_height) {}

and

Rectangle(Point _leftbottom, uint8_t _width, uint8_t _height)
    { 
      LeftBottom=_leftbottom;
      Width=_width;
      Height=_height;
    }

GolamMostafa:
Queries/Questions:

1.1) As with any struct initialization: Rectangle rect({13, 3}, 10, 20);

1.2+1.3) Not sure the question is understood, but:

Serial.println(rect.LeftBottom.X);
Serial.println(rect.Width);
  1. Both compile fine on my system :?

GolamMostafa:
2. It looks like that the following two blocks of codes of the Rectangle() constructor are not equivalent. Why not? (Sketch with the top constructor function gets compiled, and the bottom one gives error.)

One is copy construction, the other is default construction + copy assignment.

  Rectangle(Point leftbottom, uint8_t width, uint8_t height)
    : leftbottom(leftbottom), // ← copy constructor is called here
      width(width), height(height) {}
  Rectangle(Point leftbottom, uint8_t width, uint8_t height)
    // ← default constructor is called here
    { 
      this->leftbottom = leftbottom; // ← copy assignment happens here
      this->width = width;
      this->height = height;
    }

For example:

struct TestStruct {
  int i = 0;

  TestStruct() {
    Serial.println("  TestStruct::TestStruct(): Default constructor");
    Serial.print("    i = "), Serial.println(i);
  }

  TestStruct(int i)
   : i(i) {
    Serial.println("  TestStruct::TestStruct(int): Constructor with int parameter");
    Serial.print("    i = "), Serial.println(i);
  }

  TestStruct(const TestStruct &other)
   : i(other.i) {
    Serial.println("  TestStruct::TestStruct(const TestStruct &): Copy constructor");
    Serial.print("    i = "), Serial.println(i);
  }

  TestStruct &operator=(const TestStruct &other) {
    this->i = other.i;
    Serial.println("  TestStruct::operator=(const TestStruct &): Copy assignment");
    Serial.print("    i = "), Serial.println(i);
    return *this;
  }
};

struct BadStruct {
  TestStruct memberStruct;
  BadStruct(TestStruct paramStruct) {
    memberStruct = paramStruct;
  }
};

struct GoodStruct {
  TestStruct memberStruct;
  GoodStruct(TestStruct paramStruct)
   : memberStruct(paramStruct) {}
};

void setup() {
  Serial.begin(115200);
  while (!Serial);
  Serial.println("BadStruct:");
  BadStruct(42);
  Serial.println("\nGoodStruct:");
  GoodStruct(42);
}

void loop() {}

Prints:

BadStruct:
  TestStruct::TestStruct(int): Constructor with int parameter
    i = 42
  TestStruct::TestStruct(): Default constructor
    i = 0
  TestStruct::operator=(const TestStruct &): Copy assignment
    i = 42

GoodStruct:
  TestStruct::TestStruct(int): Constructor with int parameter
    i = 42
  TestStruct::TestStruct(const TestStruct &): Copy constructor
    i = 42

Umm... Not sure if this would help, but you seem to be working on a base graphics kind of setup.

This is what I use for what I think your trying to do.

baseGraphics.h

baseGraphics.cpp

-jim lee

Wow, seems like it starts big discussion.
Thank you to all participants, problem is fixed.
Have never used initializer lists, did not get syntax, but default constructor perfectly solve my problem, thank you again.
Separate thanks for such thing as "Point() = default", never ever used it, but will :slight_smile:

Danois90:
1.1) As with any struct initialization:

Rectangle rect({13, 3}, 10, 20);

Works well (sketch is given below).

1.2+1.3) Not sure the question is understood, but:

Serial.println(rect.LeftBottom.X);

Serial.println(rect.Width);

Also, works well.

  1. Both compile fine on my system :?

Execute the following sketch by removing the initializer list of Rectangle::Rectangle with the assignment statements, and you will see the compilation error which was OP's problem and was solved by with an initializer list as per Post#9.

struct Point
{
  uint8_t X = 0;
  uint8_t Y = 0;
  Point(uint8_t _x, uint8_t _y): X(_x), Y(_y) {}
  Point() = default;
};

struct Rectangle
{
  Point LeftBottom;
  uint8_t Width;
  uint8_t Height;
  Rectangle(Point _leftbottom, uint8_t _width, uint8_t _height)
    : LeftBottom(_leftbottom), Width(_width), Height(_height) {}
   //{
   //     LeftBottom = _leftbottom;
   //     Width = _width);
   //     Height = _height;  
   //   }
};

Point myDimension(12, 3);
Rectangle recta({5, 6}, 7, 8);

void setup()
{
  Serial.begin(9600);
  Serial.println(myDimension.X);  //shows: 12
  Serial.println(recta.LeftBottom.X); //shows: 5
  Serial.println(recta.Width); //shows: 7
}

void loop()
{

}

Thanks and + for giving efforts to satisfy the desires of my queries/questions.