0

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!

7
  • Now write 100 times: "C is not C++ is not C!" Commented Aug 1, 2015 at 14:52
  • It's also worth noting that unlike Java, changes made to my_button.ledLight will not change the contents of my_led. You copied the object. Commented Aug 1, 2015 at 14:53
  • @Olaf, I am really sorry and especially ashamed since I myself often ask people to do the same thing with 'Java/JavaScript'. Thanks for the edit. @BillLynch, how would I pass my_led directly to my_button? So that changes from the button affect its contents. Commented Aug 1, 2015 at 14:58
  • @YemSalat You can make ledlight a reference Commented Aug 1, 2015 at 15:09
  • @awesomeyi, like so? Light& ledLight; and then: Button(Light& l) { } in the constructor declaration? Commented Aug 1, 2015 at 15:48

2 Answers 2

7

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) { }
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks! But what is the correct syntax if I have more parameters, for example: Button(int pin, long time, Light l) ?
@YemSalat You can try Button(int pin, long time, Light l): b_pin(pin), b_time(time), ledLight(l) {}
Also, remember when you construct objects this way, they will be destroyed at the end of block (function, loop, if-clause, whatever). If you expect your Light object to live longer, you have to use new Light(0) and pass it as a pointer to Button (preferably shared pointer).
But wouldn't just re-writing it as Button(Light& l): ledLight(l) { } do the trick? Do I still need to change the way I pass it to the constructor?
@MaciejDziuban: That is not true, at all. The Light will be copied for storage. Your suggestion of dynamic allocation is going in the wrong direction.
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.

10 Comments

Wouldn't it attempt to call the default constructor instead of the one which passes the arguments?
If you explicitly define constructor, the default one won't be automatically created
@YemSalat When you do Button my_button(my_led);, you're already calling the default Light::Light() constructor to first instantiate the Light member when instantiating Button. Then you copy the value of Light provided in the Button::Button(Light) constructor.
@TJOlaes thanks heaps for the explanation! You are exactly right of what I am trying to do, and each button needs to have control over actual LEDs. However, when I run your code for the Button class I get the following error: In constructor ‘Button::Button(const Light&)’: error: cannot convert ‘const Light’ to ‘const Light*’ in assignment In this way do I still pass it to constructor with: Button my_button(my_led); i.e. will it automatially know that this is a reference to the object and it doesn't need to be copied?
My bad, I had left in some copied text in my suggested revision. I revised it accordingly. The idea is that you're passing a read-only reference of the light to the button. If you want the button to modify the light somehow (like change its status to "lit" or something), you'll want to leave out the const keywords.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.