Beginner error: "Cannot instantiate abstract class"


#1

I’m trying to strip down the FlexBox setup demonstrated here:


>Link to Original Thread

My goal is to make a simple single file version that does nothing except show the flexboxes and sliders, so that it can be easy to review/edit/repost.

However, I seem to have failed, as it says “‘MainContentComponent’: cannot instantiate abstract class 158”

Here’s my single file version “main.cpp” I was trying to build:

#include "../JuceLibraryCode/JuceHeader.h"


class LabeledSlider : public GroupComponent

{
public:
	LabeledSlider(const String& name)
	{
		setText(name);
		setTextLabelPosition(Justification::centredTop);
		addAndMakeVisible(slider);
	}

	void resized() override
	{
		slider.setBounds(getLocalBounds().reduced(10));
	}

	Slider slider
	{
		Slider::RotaryHorizontalVerticalDrag, Slider::TextBoxBelow
	};


};



class MainContentComponent : public AudioAppComponent

{
public:
	MainContentComponent()
		
	{
		
		LabeledSlider *control = new LabeledSlider("Level");
		control->slider.setRange(0.0, 1.0);
		control->slider.setSkewFactorFromMidPoint(500.0);
		control->slider.setNumDecimalPlacesToDisplay(1);
		control->slider.setValue(currentLevel, dontSendNotification);
		control->slider.onValueChange = [this] { targetLevel = (float)level.slider.getValue(); };
		control->slider.setTextBoxStyle(Slider::TextBoxBelow, false, 100, 20);
		addAndMakeVisible(knobs.add(control));

		control = new LabeledSlider("Dummy1");
		addAndMakeVisible(knobs.add(control));

		control = new LabeledSlider("Dummy2");
		addAndMakeVisible(knobs.add(control));

		control = new LabeledSlider("Dummy3");
		addAndMakeVisible(knobs.add(control));

		control = new LabeledSlider("Dummy4");
		addAndMakeVisible(knobs.add(control));

		control = new LabeledSlider("Dummy5");
		addAndMakeVisible(knobs.add(control));

		control = new LabeledSlider("Dummy6");
		addAndMakeVisible(knobs.add(control));

		control = new LabeledSlider("Dummy7");
		addAndMakeVisible(knobs.add(control));

		control = new LabeledSlider("Dummy8");
		addAndMakeVisible(knobs.add(control));

		control = new LabeledSlider("Dummy9");
		addAndMakeVisible(knobs.add(control));


		setSize(600, 600);
		
	}

	~MainContentComponent()
	{
		shutdownAudio();
	}


	void resized() override
	{
		FlexBox knobBox;
		knobBox.flexWrap = FlexBox::Wrap::wrap;
		knobBox.justifyContent = FlexBox::JustifyContent::flexStart;
		knobBox.alignContent = FlexBox::AlignContent::flexStart;

		for (auto* k : knobs)
			knobBox.items.add(FlexItem(*k).withMinHeight(80.0f).withMinWidth(80.0f).withFlex(1));

		FlexBox fb;
		fb.flexDirection = FlexBox::Direction::column;
		fb.items.add(FlexItem(knobBox).withFlex(2.5));
		fb.performLayout(getLocalBounds().toFloat());

	}


private:
	
	
	float currentLevel = 0.1f, targetLevel = 0.1f;
	int rotaryDiam = 100;

	LabeledSlider level{ "Level" };
	LabeledSlider dummy1{ "Dummy 1" };
	LabeledSlider dummy2{ "Dummy 2" };
	LabeledSlider dummy3{ "Dummy 3" };
	LabeledSlider dummy4{ "Dummy 4" };
	LabeledSlider dummy5{ "Dummy 5" };
	LabeledSlider dummy6{ "Dummy 6" };
	LabeledSlider dummy7{ "Dummy 7" };
	LabeledSlider dummy8{ "Dummy 8" };
	LabeledSlider dummy9{ "Dummy 9" };

	OwnedArray<LabeledSlider> knobs;


	JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MainContentComponent)
};




class Application    : public JUCEApplication
{
public:
    
    Application() {}

    const String getApplicationName() override       { return "SineSynthTutorial"; }
    const String getApplicationVersion() override    { return "3.0.0"; }

    void initialise (const String&) override         { mainWindow.reset (new MainWindow ("SineSynthTutorial", new MainContentComponent(), *this)); }   /// LINE 158 with the error
    void shutdown() override                         { mainWindow = nullptr; }

private:
    class MainWindow    : public DocumentWindow
    {
    public:
        MainWindow (const String& name, Component* c, JUCEApplication& a)
            : DocumentWindow (name, Desktop::getInstance().getDefaultLookAndFeel()
                                                          .findColour (ResizableWindow::backgroundColourId),
                              DocumentWindow::allButtons),
              app (a)
        {
            setUsingNativeTitleBar (true);
            setContentOwned (c, true);

           #if JUCE_ANDROID || JUCE_IOS
            setFullScreen (true);
           #else
            setResizable (true, false);
            setResizeLimits (300, 250, 10000, 10000);
            centreWithSize (getWidth(), getHeight());
           #endif

            setVisible (true);
        }

        void closeButtonPressed() override
        {
            app.systemRequestedQuit();
        }

    private:
        JUCEApplication& app;

        //==============================================================================
        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow)
    };

    std::unique_ptr<MainWindow> mainWindow;
};

//==============================================================================
START_JUCE_APPLICATION (Application)

This is meant to have no function except showing the flexbox sliders on the GUI when compiled.

I think the problem is in where I first defined MainContentComponent but I don’t know why.

Any help?


#2

It looks like you are inheriting from AudioAppComponent but don’t implement the pure virtual methods that has. (Which causes the cannot instantiate abstract class error.)


#3

What would be the simplest way to make this work? This is just meant to be a “FlexBox/GUI demo project”. It would eventually need to be applied to a synth, but right now I just want the simplest single file project I can get running so I can test/share/edit/experiment/etc.


#4

Maybe inheriting from plain Component instead of AudioAppComponent could work.


#5

You’re a genius! (Well at least it seems at least that way from the perspective of my ignorance :slight_smile: )

It worked.

Here’s the code:

#include "../JuceLibraryCode/JuceHeader.h"

///============================
///BEGINNING OF USUAL PROJECT HEADER


#pragma once


class LabeledSlider : public GroupComponent

{
public:
	LabeledSlider(const String& name)
	{
		setText(name);
		setTextLabelPosition(Justification::centredTop);
		addAndMakeVisible(slider);
	}

	void resized() override
	{
		slider.setBounds(getLocalBounds().reduced(10));
	}

	Slider slider
	{
		Slider::RotaryHorizontalVerticalDrag, Slider::TextBoxBelow
	};


};


class MainContentComponent : public Component

{
public:
	MainContentComponent()
		
	{

		LabeledSlider *control = new LabeledSlider("Level");
		control->slider.setRange(0.0, 1.0);
		control->slider.setSkewFactorFromMidPoint(500.0);
		control->slider.setNumDecimalPlacesToDisplay(1);
		control->slider.setValue(currentLevel, dontSendNotification);
		control->slider.onValueChange = [this] { targetLevel = (float)level.slider.getValue(); };
		control->slider.setTextBoxStyle(Slider::TextBoxBelow, false, 100, 20);
		addAndMakeVisible(knobs.add(control));

		control = new LabeledSlider("Dummy1");
		addAndMakeVisible(knobs.add(control));

		control = new LabeledSlider("Dummy2");
		addAndMakeVisible(knobs.add(control));

		control = new LabeledSlider("Dummy3");
		addAndMakeVisible(knobs.add(control));

		control = new LabeledSlider("Dummy4");
		addAndMakeVisible(knobs.add(control));

		control = new LabeledSlider("Dummy5");
		addAndMakeVisible(knobs.add(control));

		control = new LabeledSlider("Dummy6");
		addAndMakeVisible(knobs.add(control));

		control = new LabeledSlider("Dummy7");
		addAndMakeVisible(knobs.add(control));

		control = new LabeledSlider("Dummy8");
		addAndMakeVisible(knobs.add(control));

		control = new LabeledSlider("Dummy9");
		addAndMakeVisible(knobs.add(control));


		setSize(600, 600);
		
	}

	~MainContentComponent()
	{
	//	shutdownAudio();
	}


	void resized() override
	{
		FlexBox knobBox;
		knobBox.flexWrap = FlexBox::Wrap::wrap;
		knobBox.justifyContent = FlexBox::JustifyContent::flexStart;
		knobBox.alignContent = FlexBox::AlignContent::flexStart;

		for (auto* k : knobs)
			knobBox.items.add(FlexItem(*k).withMinHeight(80.0f).withMinWidth(80.0f).withFlex(1));

		FlexBox fb;
		fb.flexDirection = FlexBox::Direction::column;
		fb.items.add(FlexItem(knobBox).withFlex(2.5));
		fb.performLayout(getLocalBounds().toFloat());

	}


private:
	
	float currentLevel = 0.1f, targetLevel = 0.1f;
	
	LabeledSlider level{ "Level" };
	LabeledSlider dummy1{ "Dummy 1" };
	LabeledSlider dummy2{ "Dummy 2" };
	LabeledSlider dummy3{ "Dummy 3" };
	LabeledSlider dummy4{ "Dummy 4" };
	LabeledSlider dummy5{ "Dummy 5" };
	LabeledSlider dummy6{ "Dummy 6" };
	LabeledSlider dummy7{ "Dummy 7" };
	LabeledSlider dummy8{ "Dummy 8" };
	LabeledSlider dummy9{ "Dummy 9" };

	OwnedArray<LabeledSlider> knobs;


	JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MainContentComponent)
};




///============================
///BEGINNING OF USUAL MAIN.CPP
class Application    : public JUCEApplication
{
public:
     Application() {}

    const String getApplicationName() override       { return "SineSynthTutorial"; }
    const String getApplicationVersion() override    { return "3.0.0"; }

    void initialise (const String&) override         { mainWindow.reset (new MainWindow ("SineSynthTutorial", new MainContentComponent(), *this)); }
    void shutdown() override                         { mainWindow = nullptr; }

private:
    class MainWindow    : public DocumentWindow
    {
    public:
        MainWindow (const String& name, Component* c, JUCEApplication& a)
            : DocumentWindow (name, Desktop::getInstance().getDefaultLookAndFeel()
                                                          .findColour (ResizableWindow::backgroundColourId),
                              DocumentWindow::allButtons),
              app (a)
        {
            setUsingNativeTitleBar (true);
            setContentOwned (c, true);

           #if JUCE_ANDROID || JUCE_IOS
            setFullScreen (true);
           #else
            setResizable (true, false);
            setResizeLimits (300, 250, 10000, 10000);
            centreWithSize (getWidth(), getHeight());
           #endif

            setVisible (true);
        }

        void closeButtonPressed() override
        {
            app.systemRequestedQuit();
        }

    private:
        JUCEApplication& app;

        //==============================================================================
        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow)
    };

    std::unique_ptr<MainWindow> mainWindow;
};

//==============================================================================
START_JUCE_APPLICATION (Application)

It just has one remaining quirk now. Most of the knobs are dummy knobs just to test with. But the level slider as you can see is meant to have some more realistic functions built in. This is malfunctioning though. If I grab the slider and move it at all, it jumps to value “1.0”, and I can’t slide it away from this. I can however type in a new value in the box below. But I can’t drag it once it jumps like this.

Is there something obviously wrong with the way it’s set up?