Reputation: 75
First of all, I'd like to apologize in advance if the answer is obvious; I am very new to C++ and my first language is Java. I am also new to Stack Overflow, so if something is wrong with my question or you need anything else, please tell me.
So. I have this piece of code here: (I am using SFML for the vector and the CircleShape)
Ball::Ball() {
// This ugly thing calls the full constructor with a random x and y position
// in such a way the the entire ball is inside the screen.
Ball::Ball((rand() % (WINDOW_X - (2 * BALL_RADIUS))) + BALL_RADIUS, (rand() % (WINDOW_Y - (2 * BALL_RADIUS))) + BALL_RADIUS);
}
Ball::Ball(float x, float y) {
loc.x = x;
loc.y = y;
ball.setPosition(loc.x - BALL_RADIUS, loc.y - BALL_RADIUS);
ball.setRadius(BALL_RADIUS);
ball.setFillColor(sf::Color::Red);
ball.setOutlineColor(sf::Color::Black);
ball.setOutlineThickness(1);
}
And here is the header (#included into the above file):
class Ball {
private:
sf::CircleShape ball;
sf::Vector2f loc;
sf::Vector2f vel;
sf::Vector2f acc;
void update();
void bounce();
void draw();
public:
Ball();
Ball(float x, float y);
void run();
};
When I create the ball with
Ball ball;
(and yes, all of the SFML rendering stuff works), it never shows. A bit of investigation shows that its loc.x and loc.y variables are not set, and probably, neither are the radius, fillcolor, etc of the ball object. If I print the values of these with std::cout inside the constructor, loc.x and loc.y and all the others are set, so I assume that they get unset somewhere after the constructor. What is strange is that if I create the ball with
Ball ball((rand() % (WINDOW_X - (2 * BALL_RADIUS))) + BALL_RADIUS, (rand() % (WINDOW_Y - (2 * BALL_RADIUS))) + BALL_RADIUS);
or even
Ball ball(400, 300);
everything works perfectly, and the ball shows up on-screen. I am really stumped guys. If anyone could help me, that would be great.
BTW, I am running OS X 10.8 with Xcode 4.5.2, and using SFML RC2.0, if that makes any difference.
Thanks,
Matt
Upvotes: 5
Views: 486
Reputation: 24153
Other answers give the syntactically correct way to do this.
I would make something semantically correct so that you call it as so:
Ball ball = Ball::createRandom();
You implement createRandom
as a static
function of Ball
:
class Ball {
public:
//...
static Ball createRandom();
};
Implemented as:
int randomisePosition(int position) {
return (rand() % (position - (2 * BALL_RADIUS))) + BALL_RADIUS;
}
Ball Ball::createRandom() {
return Ball(randomisePosition(WINDOW_X),
randomisePosition(WINDOW_Y));
}
Upvotes: 1
Reputation: 19453
Constructor Chaining is not supported in C++ before C++ 11
You can take the logic to a function and call it from both constructor. something like:
Ball::Ball() {
// This ugly thing calls the full constructor with a random x and y position
// in such a way the the entire ball is inside the screen.
init((rand() % (WINDOW_X - (2 * BALL_RADIUS))) + BALL_RADIUS, (rand() % (WINDOW_Y - (2 * BALL_RADIUS))) + BALL_RADIUS);
}
Ball::Ball(float x, float y) {
init(x,y);
}
Ball::init(float x, float y) {
loc.x = x;
loc.y = y;
ball.setPosition(loc.x - BALL_RADIUS, loc.y - BALL_RADIUS);
ball.setRadius(BALL_RADIUS);
ball.setFillColor(sf::Color::Red);
ball.setOutlineColor(sf::Color::Black);
ball.setOutlineThickness(1);
}
Upvotes: 3
Reputation: 2293
You should make a init() method and call it in both of your constructors.
Ball::Ball((rand() % (WINDOW_X - (2 * BALL_RADIUS))) + BALL_RADIUS, (rand() % (WINDOW_Y - (2 * BALL_RADIUS))) + BALL_RADIUS);
creates a temp ball object and destroys it right away
Upvotes: 0
Reputation: 110728
Calling a constructor from another constructor (known as delegating a constructor) was impossible before C++11. To do it in C++11, you need to use the member initialisation list:
Ball::Ball()
: Ball((rand() % (WINDOW_X - (2 * BALL_RADIUS))) + BALL_RADIUS,
(rand() % (WINDOW_Y - (2 * BALL_RADIUS))) + BALL_RADIUS)
{ }
Pre-C++11, you can create another function that does the common work and get both constructors to call it.
Ball::Ball() {
init((rand() % (WINDOW_X - (2 * BALL_RADIUS))) + BALL_RADIUS,
(rand() % (WINDOW_Y - (2 * BALL_RADIUS))) + BALL_RADIUS);
}
Ball::Ball(float x, float y) {
init(x, y);
}
void Ball::init(float x, float y) {
loc.x = x;
loc.y = y;
ball.setPosition(loc.x - BALL_RADIUS, loc.y - BALL_RADIUS);
ball.setRadius(BALL_RADIUS);
ball.setFillColor(sf::Color::Red);
ball.setOutlineColor(sf::Color::Black);
ball.setOutlineThickness(1);
}
Upvotes: 7
Reputation: 63250
I would suggest instead of doing constructor chaining, that you use two-phase initialization, which would mean you create an init()
function which you call in your default constructor.
Upvotes: 1
Reputation: 9642
Constructor chaining in C++ isn't allowed, instead, what will be happening here is that a temporary version of your class will be created, not assigned anywhere, then discarded.
Instead, make a private initialisation method with the parameters you want and call that from your constructors with the correct parameters.
Upvotes: 3