[ C++: how to pass an object to another object constructor? ]
I know this question is asked a lot, but I come from Java and I haven't done any C/C++ for a very long time.
Can you please remind me how to correctly pass an object to another object's constructor in C++?
For example, I need to pass a new Light object to the Button constructor:
// LED Light
class Light {
int pin;
public:
Light(int p) {
pin = p;
}
};
// BUTTON
class Button {
Light ledLight;
public:
Button(Light l) {
ledLight = l;
}
};
Light my_led(0);
Button my_button(my_led);
This is how I would do it in a Java-like fasion. However this produces the following error:
:: In constructor ‘Button::Button(Light)’:
:: 16:19: error: no matching function for call to ‘Light::Light()’
:: 16:19: note: candidates are:
:: 6:3: note: Light::Light(int)
:: 6:3: note: candidate expects 1 argument, 0 provided
:: 2:7: note: Light::Light(const Light&)
:: 2:7: note: candidate expects 1 argument, 0 provided
Is the object being passed by reference or is it attempting to create a new one when I create a new Button?
Or do I need to declare the Light as a pointer in the Button's constructor?
Any help is much apreciated!
Answer 1
The program tries to initiate ledLight
using the default constructor and then assigns l
to ledLight
. The compiler gives you an error because there is no default constructor for Light
. Try this instead:
Button(Light l): ledLight(l) { }
Answer 2
You're missing a default constructor. Try modifying your class like this:
class Light {
int pin;
public:
Light()=default; //<-- put this in
Light(int p) {
pin = p;
}
};
As to why you're not automatically generating a default constructor, it's because you're already declaring a constructor of some type, so the compiler won't generate a default one (from http://en.cppreference.com/w/cpp/language/default_constructor, see sections on implicitly declared/defined constructors).
In response to the comment:
Wouldn't it attempt to call the default constructor instead of the one which passes the arguments?
When your executing code gets to the last line:
Button my_button(my_led);
You're instantiating a Button
and a Light
as part of the Button
instantiation process. Without specifying a default Light::Light()
constructor, you're leaving out instructions on how to instantiate a Light
object without a value, which you need to do before copying the value of my_led
into my_button. You'll get the results you intended, you're just currently leaving out instructions to the compiler on how to perform an intermediate step, i.e. instantiate Light
without any arguments.
Some things to think about:
What are you really trying to do? Just by looking at your instruction code:
Light my_led(0);
Button my_button(my_led);
It seems to me like you're trying to say "a light named my_led
exists" and "a button named my_button
exists and needs my_led
". Do you want the button to refer to a specific LED that exists already, or just an LED that has the same values?
If you think you'll want to refer to the actual LED from that button then you might want to consider doing the following:
class Button {
const Light *ledLight;
public:
Button(const Light& l) :
ledLight{&l}
{}
};
That way, your Button
has a pointer to the Light
you created, and whatever you do with the Light
inside your Button
code will be performed on the Light
object you already instantiated, instead of some separate copy of Light
you create by copy-constructing Light
with your current Button
constructor.
If you want the button to actually modify the light, revise Button
like so:
class Button {
// constant reference to changeable object
Light * const ledLight;
public:
/**
* You're providing a reference to a light that can be changed
* (i.e. button code can toggle lit status or something)
*/
Button(Light & l) :
ledLight{&l}
{}
};
The above you could think of as having an unchanging wire from the button to the LED. If you think you'll be reassigning the LED that gets lit from the button, you'd take out the const
keyword from the pointer member in Button
as well.