2

So for one of my assignments i have to generate random graphic circles and rectangles, using structures. but i cannot fathom how to get the structure to output from a functions.

   struct Circle{
   int x;
     int y;
     int radius;
     int r;
     int g;
     int b;
   };

   Circle createCirc() {
     int x = rand() % window_Width;
     int y = rand() % window_Height;
     int radius = rand() % 100;
     int r = rand()%256;
     int g = rand()%256;
     int b = rand()%256;
     return Circle(x,y,radius,r,g,b);
   }

here i create the struct with basic values for the object, then i pass some data from main into this function.

 Circle circle[1000];
 circle[count] = createCirc();

however i cannot even get it to run as apparently when defining the struct itself it comes with this error:

main.cpp:47:8: note: candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 6 were provided

I just do not understand how to pass the data from the function into the varable in main.

4 Answers4

10

You can use

 return Circle(x,y,radius,r,g,b);

only when there is an explicitly defined constructor that takes those arguments. Change it to:

 return {x,y,radius,r,g,b};

The second form uses aggregate initialization to construct a Circle.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
1
struct Circle {
    int x;
    int y;
    int radius;
    int r;
    int g;
    int b;
};

You are only defining fields to the class, but not a constructor.

The () initialization syntax does not allow to do what you're doing.
However, C++11 aggregate-initialization can, as pointed out by @RSahu 's post.

An alternative is to define a constructor to your class, optionally using the member-initialization list (see a few reasons here why to).

Essentially, it would do what your createCirc function is attempting to do. You would define it as such:

struct Circle {
    int x, y, radius, r, g, b;

    Circle();
};

Circle::Circle() :
    x{rand() % window_width},
    y{rand() % window_height},
    radius{rand() % 100},
    r{rand() % 256},
    g{rand() % 256},
    b{rand() % 256}
{}

This would allow you to do something like Circle myCircle; and it will get initialized as you expect.

That being said, a constructor is not necessarily the best way to do this (IMO it hides too much behavior here) but it's a good thing to know.

asu
  • 1,875
  • 17
  • 27
  • Actually, I'm not sure - is `return {a, b, c};` aggregate initialization or something different entirely? I know that it's not the same as `return SomeClass{a, b, c};`. – asu Nov 06 '18 at 19:24
  • 1
    It is. "using the member-initialization list" Why not show that as an example and explain why it is usually prefered to assignment in the ctors body? – Swordfish Nov 06 '18 at 19:26
  • @Swordfish Thanks, I've modified my example to use the member initialization list. I feel like that it's not terribly relevant in this particular case (it's pure data) so I linked to another SO post which gives more general information about it. I was not sure how to sum it up so I rather didn't. – asu Nov 06 '18 at 19:34
1

Just create a new Circle inside your createCirc() function and return it:

Circle createCirc() {
    Circle circle;
    circle.x = rand() % window_Width;
    circle.y = rand() % window_Height;
    circle.radius = rand() % 100;
    circle.r = rand()%256;
    circle.g = rand()%256;
    circle.b = rand()%256;
    return circle;
}

Also you should think about using a vector for dynamic allocation and storage.

Samy Dressel
  • 143
  • 1
  • 13
  • wouldnt that dismiss the point of trying to have multiple circles if its returning itself? – Snowballion Fisher Nov 06 '18 at 19:37
  • its not returning itself, the function createCirc() is just initializing a new Circle-Object and returning it - this has nothing to do with your struct and default values of it. – Samy Dressel Nov 06 '18 at 19:45
  • 1
    Better to turn `createCirc` into a constructor. – user4581301 Nov 06 '18 at 20:01
  • 1
    This constructs a temporary `Circle` and makes a copy for the caller to copy into the array they're actually going to use. The larger the object gets, the more important this is – Tim Randall Nov 06 '18 at 20:27
0

The following should work nicely.

struct Circle
{
    Circle(); // the default constructor
    int x;
    int y;
    int radius;
    int r;
    int g;
    int b;
};

Circle::Circle() : // start member-initialization list
   x( rand() % window_Width ),
   y( rand() % window_Height ),
   radius( rand() % 100 ),
   r( rand()%256 ),
   g( rand()%256 ),
   b( rand()%256 )
{
    // nothing to do!
}

I choose this implementation for a couple of reasons. The main reason is that you want to construct 1000 of these and store them in an array. When an array of objects is created (assuming it isn't an array of int or other plain data type) the default constructor will be called for each element. That's what we defined here. And by using the member-initialization list we get those initial values into the member variables more efficiently than we would by assigning them in the body of the constructor. That isn't terribly important for int values, but it's a good habit to get into.

Note that if you wanted to construct Circles with other values, it would be a waste of time to use this default constructor. You'd want to define another constructor that takes parameters for size, position, and/or RGB values.

Tim Randall
  • 4,040
  • 1
  • 17
  • 39