Unimplemented pure virtual method

Hello,

It’s my first day in Juce and I am trying to build a code example.
I get the error message “Unimplemented pure virtual method” in the following code block (location indicated).

I have checked the documentation and tried overriding the variable to no avail. Please help.

  class JUCE_API  Listener
    {
    public:
        /** Destructor. */
        virtual ~Listener() = default;

        /** Called when the button is clicked. */
        
        virtual void buttonClicked (Button*) = 0; `1. Unimplemented pure virtual method 'buttonClicked' in 'ParametricEQAudioProcessorEditor'`
    
        /** Called when the button's state changes. */
        virtual void buttonStateChanged (Button*)  {}
    };

Pure virtual functions are intentionally not implented so that you have to override that method.

The reason is, that the API architects believed there is no point in inheriting Button::Listener and not implementing buttonClicked.

You can still implement it with an empty function body.

Can you show, how you tried? It should look like

void buttonClicked (juce::Button*) override {}

Thank you.
I entered the line

virtual void buttonClicked (Button*) override {}

I tried it without the virtual as well.

and got the error:

'buttonClicked' marked 'override' but does not override any member functions

Build succeeded!

It generated a couple more of the same error and the solution was to delete “override” (automatically suggested).

If that solved the issue, it means that it no longer overrides a method.

a) does your ParametricEQAudioProcessorEditor inherit juce::Button::Listener?
b) did you use the same namespace as argument void buttonClicked (juce::Button*) override?

If this is a new project, you might need to add juce:: before all juce classes…

Without seeing the code I guess your buttonClicked() callback will never be called, because it is unknown. If it was known, the override should not have complained.

Which example are you trying to build?

The parametriceq example from the Reiss McPherson Audio Effects book.

That book seems to be pretty old (2014), so it isn’t that surprising if the examples don’t build or work correctly anymore with the later versions of Juce.

As I said, I managed to get it working. Thank you to @daniel for helping me with the issue I posted here. Not sure what your point is @xenakios .

As Daniel said, if that “fixed it”, then you’ve only killed that error, not fixed the problem. The “override” specifier says that the function overrides the (pure virtual) function for which you initially got an error. If you implement a function that is called buttonClicked, but which does not override the base class’ function, then you’re simply implementing a new member function that will never be called (at least as a Listener).

I think you should post what your derived class actually looks like in its entirety. Something is wrong here. You were originally not overriding a function that you had to override, then you changed it so that the function you added does not override the base class function. It can’t be both ways. You must have changed something else that we can’t see.

2 Likes

Hello, thank you for your help.
Not sure if I’m doing this right, but I think this is what you’re asking for:

class JUCE_API  Button  : public Component,
                          public SettableTooltipClient
{
protected:
    //==============================================================================
    explicit Button (const String& buttonName);

public:
    /** Destructor. */
    ~Button() override;

    //==============================================================================
    void setButtonText (const String& newText);

    const String& getButtonText() const               { return text; }

    //==============================================================================

    bool isDown() const noexcept;

    bool isOver() const noexcept;

    //==============================================================================
    void setToggleState (bool shouldBeOn, NotificationType notification);

    bool getToggleState() const noexcept                        { return isOn.getValue(); }


    Value& getToggleStateValue() noexcept                       { return isOn; }

    void setClickingTogglesState (bool shouldAutoToggleOnClick) noexcept;


    bool getClickingTogglesState() const noexcept;

    //==============================================================================
    void setRadioGroupId (int newGroupId, NotificationType notification = sendNotification);

    /** Returns the ID of the group to which this button belongs.
        (See setRadioGroupId() for an explanation of this).
    */
    int getRadioGroupId() const noexcept                        { return radioGroupId; }

    //==============================================================================

    class JUCE_API  Listener
    {
    public:
        /** Destructor. */
        virtual ~Listener() = default;

        /** Called when the button is clicked. */
        virtual void buttonClicked (Button*) = 0;

        /** Called when the button's state changes. */
        virtual void buttonStateChanged (Button*)  {}
    };


    void addListener (Listener* newListener);

    /** Removes a previously-registered button listener
        @see addListener
    */
    void removeListener (Listener* listener);

    //==============================================================================
    /** You can assign a lambda to this callback object to have it called when the button is clicked. */
    std::function<void()> onClick;

    /** You can assign a lambda to this callback object to have it called when the button's state changes. */
    std::function<void()> onStateChange;

    //==============================================================================
    virtual void triggerClick();

    //==============================================================================
    void setCommandToTrigger (ApplicationCommandManager* commandManagerToUse,
                              CommandID commandID,
                              bool generateTooltip);

    /** Returns the command ID that was set by setCommandToTrigger(). */
    CommandID getCommandID() const noexcept             { return commandID; }

    //==============================================================================

    void addShortcut (const KeyPress&);


    void clearShortcuts();

    bool isRegisteredForShortcut (const KeyPress&) const;

    //==============================================================================

    void setRepeatSpeed (int initialDelayInMillisecs,
                         int repeatDelayInMillisecs,
                         int minimumDelayInMillisecs = -1) noexcept;

    void setTriggeredOnMouseDown (bool isTriggeredOnMouseDown) noexcept;

    bool getTriggeredOnMouseDown() const noexcept;

    uint32 getMillisecondsSinceButtonDown() const noexcept;

    //==============================================================================

    void setTooltip (const String& newTooltip) override;

//==============================================================================
    /** A combination of these flags are used by setConnectedEdges(). */
    enum ConnectedEdgeFlags
    {
        ConnectedOnLeft = 1,
        ConnectedOnRight = 2,
        ConnectedOnTop = 4,
        ConnectedOnBottom = 8
    };

    void setConnectedEdges (int connectedEdgeFlags);

    /** Returns the set of flags passed into setConnectedEdges(). */
    int getConnectedEdgeFlags() const noexcept          { return connectedEdgeFlags; }

    bool isConnectedOnLeft() const noexcept             { return (connectedEdgeFlags & ConnectedOnLeft) != 0; }

    bool isConnectedOnRight() const noexcept            { return (connectedEdgeFlags & ConnectedOnRight) != 0; }

    bool isConnectedOnTop() const noexcept              { return (connectedEdgeFlags & ConnectedOnTop) != 0; }

    /** Indicates whether the button adjoins another one on its bottom edge.
        @see setConnectedEdges
    */
    bool isConnectedOnBottom() const noexcept           { return (connectedEdgeFlags & ConnectedOnBottom) != 0; }


    //==============================================================================
    /** Used by setState(). */
    enum ButtonState
    {
        buttonNormal,
        buttonOver,
        buttonDown
    };

    void setState (ButtonState newState);

    /** Returns the button's current over/down/up state. */
    ButtonState getState() const noexcept               { return buttonState; }

    //==============================================================================

    struct JUCE_API  LookAndFeelMethods
    {
        virtual ~LookAndFeelMethods() = default;

        virtual void drawButtonBackground (Graphics&, Button&, const Colour& backgroundColour,
                                           bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) = 0;

        virtual Font getTextButtonFont (TextButton&, int buttonHeight) = 0;
        virtual int getTextButtonWidthToFitText (TextButton&, int buttonHeight) = 0;

        /** Draws the text for a TextButton. */
        virtual void drawButtonText (Graphics&, TextButton&,
                                     bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) = 0;

        /** Draws the contents of a standard ToggleButton. */
        virtual void drawToggleButton (Graphics&, ToggleButton&,
                                       bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) = 0;

        virtual void changeToggleButtonWidthToFitText (ToggleButton&) = 0;

        virtual void drawTickBox (Graphics&, Component&, float x, float y, float w, float h,
                                  bool ticked, bool isEnabled,
                                  bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) = 0;

        virtual void drawDrawableButton (Graphics&, DrawableButton&,
                                         bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) = 0;
    };

    // This method's parameters have changed - see the new version.
    JUCE_DEPRECATED (void setToggleState (bool, bool));

protected:
    //==============================================================================
    /** This method is called when the button has been clicked.

        Subclasses can override this to perform whatever actions they need to do.
        In general, you wouldn't use this method to receive clicks, but should get your callbacks
        by attaching a std::function to the onClick callback, or adding a Button::Listener.
        @see triggerClick, onClick
    */
    virtual void clicked();

    /** This method is called when the button has been clicked.

        By default it just calls clicked(), but you might want to override it to handle
        things like clicking when a modifier key is pressed, etc.

        @see ModifierKeys
    */
    virtual void clicked (const ModifierKeys& modifiers);

    /** Subclasses should override this to actually paint the button's contents.

        It's better to use this than the paint method, because it gives you information
        about the over/down state of the button.

        @param g                                the graphics context to use
        @param shouldDrawButtonAsHighlighted    true if the button is either in the 'over' or 'down' state
        @param shouldDrawButtonAsDown           true if the button should be drawn in the 'down' position
    */
    virtual void paintButton (Graphics& g,
                              bool shouldDrawButtonAsHighlighted,
                              bool shouldDrawButtonAsDown) = 0;

    /** Called when the button's up/down/over state changes.

        Subclasses can override this if they need to do something special when the button
        goes up or down.

        @see isDown, isOver
    */
    virtual void buttonStateChanged();

    //==============================================================================
    /** @internal */
    virtual void internalClickCallback (const ModifierKeys&);
    /** @internal */
    void handleCommandMessage (int commandId) override;
    /** @internal */
    void mouseEnter (const MouseEvent&) override;
    /** @internal */
    void mouseExit (const MouseEvent&) override;
    /** @internal */
    void mouseDown (const MouseEvent&) override;
    /** @internal */
    void mouseDrag (const MouseEvent&) override;
    /** @internal */
    void mouseUp (const MouseEvent&) override;
    /** @internal */
    bool keyPressed (const KeyPress&) override;
    /** @internal */
    using Component::keyStateChanged;
    /** @internal */
    void paint (Graphics&) override;
    /** @internal */
    void parentHierarchyChanged() override;
    /** @internal */
    void visibilityChanged() override;
    /** @internal */
    void focusGained (FocusChangeType) override;
    /** @internal */
    void focusLost (FocusChangeType) override;
    /** @internal */
    void enablementChanged() override;

private:
    //==============================================================================
    Array<KeyPress> shortcuts;
    WeakReference<Component> keySource;
    String text;
    ListenerList<Listener> buttonListeners;

    struct CallbackHelper;
    std::unique_ptr<CallbackHelper> callbackHelper;
    uint32 buttonPressTime = 0, lastRepeatTime = 0;
    ApplicationCommandManager* commandManagerToUse = nullptr;
    int autoRepeatDelay = -1, autoRepeatSpeed = 0, autoRepeatMinimumDelay = -1;
    int radioGroupId = 0, connectedEdgeFlags = 0;
    CommandID commandID = {};
    ButtonState buttonState = buttonNormal, lastStatePainted = buttonNormal;

    Value isOn;
    bool lastToggleState = false;
    bool clickTogglesState = false;
    bool needsToRelease = false;
    bool needsRepainting = false;
    bool isKeyDown = false;
    bool triggerOnMouseDown = false;
    bool generateTooltip = false;

    void repeatTimerCallback();
    bool keyStateChangedCallback();
    void applicationCommandListChangeCallback();
    void updateAutomaticTooltip (const ApplicationCommandInfo&);

    ButtonState updateState();
    ButtonState updateState (bool isOver, bool isDown);
    bool isShortcutPressed() const;
    void turnOffOtherButtonsInGroup (NotificationType click, NotificationType state);

    void flashButtonState();
    void sendClickMessage (const ModifierKeys&);
    void sendStateMessage();
    void setToggleState (bool shouldBeOn, NotificationType click, NotificationType state);

    bool isMouseSourceOver (const MouseEvent& e);

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Button)
};


} // namespace juce

Thank you.

Ok, now I’m seriously confused. You’re editing the Juce Button class code? Why? Leave it alone.

You haven’t said if your original code was creating a new class derived from juce::Button, or if you simply have a Component class that includes Button::Listener as a superclass. I am guessing the latter.

In that case, you simply need to declare:

void buttonClicked( juce::Button*) override;

in your Component’s class definition, and define the function’s contents there or in a separate .cpp file. (Assuming you intend your Component to be a Button::Listener, of course. If not, then simply remove the “public Button::Listener” from the class declaration.)