Object constructor confusion

Apologies for the noob question. I’m trying to define an object DrumPad for example.

{
public:
	DrumPad()
	{
	}

	DrumPad(TextButton button, String number)
	{
		_buttontype = button; // problem is here!
		_noteNumber = number;
	}
private:
	TextButton _buttontype;
	String _noteNumber;
};

And the message is:
'No 'operator =' matches arguments of type 'juce::TextButton' and 'juce::TextButton''

Why is this not working?

Juce Component is not copyable so you can’t pass them around as values. Use a pointer or reference to the component instead. In that case the passed component of course has to live as long as the object where it was passed. (So don’t have the component for example as a local variable anywhere.)

Here using a reference (note that the default constructor has to be removed because of the reference member, references always have to be initialized) :

{
public:
	DrumPad(TextButton& button, String number)
          : _buttontype(button)
	{
		
		_noteNumber = number;
	}
private:
	TextButton& _buttontype;
	String _noteNumber;
};

Also note that several DrumPad objects probably shouldn’t be referencing the same TextButton object, is that what you are trying to do in the code?

1 Like

Thanks for the speedy reply :slight_smile:

So as soon as a class has a member that is a reference type then it must be initialized from the constructor and that removes any possibility of an empty default constructor?

What makes an object copyable or not?

No, I was trying to give each ‘DrumPad’ object its own TextButton property.

By having an assignment operator. Many juce classes disable the default copy constructor and assignment operator intentionally.

And N.B. please refrain from using leading underscores, as they are reserved in C++ see

However, I am aware, that it is technically legit, since it is in your class namespace, but it is misleading…

1 Like

If you need to be able to create the object with the default constructor and only later make it point to the other object, you can use a pointer member for the object. (TextButton* member instead of TextButton& in your case.)

If the constructors and/or copy assignment operators are private, the object becomes non-copyable. Juce has a macro to achieve that and many of the Juce classes use that to prevent typical mistakes.

1 Like

noted

So how about having several ‘DrumPad’ objects having a TextButton property that is not a reference to the same TextButton?

Version using a pointer :

{
public:
	DrumPad()
	{
	}

	DrumPad(TextButton* button, String number)
	{
		_buttontype = button; 
		_noteNumber = number;
	}
private:
	TextButton* _buttontype=nullptr;
	String _noteNumber;
};
1 Like

Much obliged :wink:

Another option is to have the button be a std::optional<TextButton>. Then, you can default-construct it as nullopt, and construct it properly later on.

1 Like

With a Juce Component it would need to be an optional to a reference, though and from cppreference.com :

“There are no optional references; a program is ill-formed if it instantiates an optional with a reference type.”

hmm, thanks that is interesting. I was just curious about still having the default constructor and usually prefer to make sure an object is ‘fully constructed’ from the get-go but it’s interesting to hear of other possibilities

I may have missed it, but do you need to create the TextButton outside of the DrumPad? ie. could the DrumPad just own the TextButton?

1 Like

Sure, that’s a possibility! So instantiate a TextButton inside the DrumPad object? To be honest, I’m just trying to work my way through some of the tutorials but I keep wandering off course trying to modify the examples.

Yes. As in your initial code example, having TextButton as a member of DrumPad has already instantiated it. It’s more a matter of where it is configured. But yes, do all of that in the DrumPad class, since it seems like the DrumPad owns the TextButton.

One of the important parts of answering your initial question is, what is it you are trying to do?

1 Like

hehe, i’m afraid that I’m not being very structured right now - i’m just trying to get a grasp on how C++ objects are put together - sorry :pleading_face:

But could you show an example of how to define the class such that I could configure the TextButton after instantiating the DrumPad? More like this perhaps…

class DrumPadV2
{
public:

	TextButton* getButton() const { return myButton; }
	String noteNumber;

	DrumPadV2(String midiNoteNumber)
	{
		noteNumber = midiNoteNumber;
	}

private:
	TextButton* myButton;
};

That class wouldn’t work at all, because the TextButton object isn’t initialized anywhere. If you want to make the DrumPad object own the TextButton, you could probably just have it as a value member. (That would make the DrumPad object itself non-copyable also, though…)

private:
	TextButton myButton;

And why not make the DrumPad object initialize the TextButton (text etc) as needed?

But if TextButton is just a private member, how could it be configured or accessed?