Why juce::Font class is declared as final?

I have a lot of font object declarations over 500+. I want to give them default scale (and other styles later) via derived class, I dont want to change juce::Font implementation. But i saw Font is final class, I cant derive it to make a Customized Font class.

The Font class doesn’t have any virtual methods, it’s not really designed to be derived from. Inheritance is for polymorphism and I don’t think we need that here. Generally speaking I would strongly encourage composition over inheritance wherever possible.

Take the following example

#include <iostream>
#include <memory>

struct FontNoVirtual 
{
    FontNoVirtual() { std::cout << __FUNCTION__ << '\n'; }
    ~FontNoVirtual() { std::cout << __FUNCTION__ << '\n'; }
};

struct FontNoVirtualDerived : public FontNoVirtual
{
    FontNoVirtualDerived() { std::cout << __FUNCTION__ << '\n'; }
    ~FontNoVirtualDerived() { std::cout << __FUNCTION__ << '\n'; }
};

struct FontVirtual 
{
    FontVirtual() { std::cout << __FUNCTION__ << '\n'; }
    virtual ~FontVirtual() { std::cout << __FUNCTION__ << '\n'; }
};

struct FontVirtualDerived : public FontVirtual
{
    FontVirtualDerived() { std::cout << __FUNCTION__ << '\n'; }
    ~FontVirtualDerived() override { std::cout << __FUNCTION__ << '\n'; }
};

int main()
{
    {
        std::unique_ptr<FontNoVirtual> font;
        font = std::make_unique<FontNoVirtualDerived>();
    }

    std::cout << '\n';

    {
        std::unique_ptr<FontVirtual> font;
        font = std::make_unique<FontVirtualDerived>();
    }

    return 0;
}

The output of this is

FontNoVirtual
FontNoVirtualDerived
~FontNoVirtual

FontVirtual
FontVirtualDerived
~FontVirtualDerived
~FontVirtual

Note that when the destructor is not marked virtual the derived destructor is not called when a pointer to the derived class is deleted!

By us marking Font final we’re able to prevent code from compiling that might make this mistake.

In this instance I think what I’ve normally seen is some free functions that return the Font with the style desired.

For example something like (untested)

static const Font& getMyMainApplicationFont()
{
    static Font font { "Helvetica" }.withStyle (Font::bold | Font::underlined)
                                    .withHeight (25);
    return font;
}

You could have multiple of these functions, or you could add a parameter or two to the function to suit your needs. For example (again untested)…

enum class FontStyle
{
    heading1,
    heading2,
    paragraph
}

template <FontStyle  style>
static const Font& getApplicationFont();

static const Font& getApplicationFont<FontStyle::heading1>()
{
    static Font font { "Helvetica" }.withStyle (Font::bold | Font::underlined)
                                    .withHeight (50);
    return font;
}

static const Font& getApplicationFont<FontStyle::heading2>()
{
    static Font font { "Helvetica" }.withStyle (Font::bold)
                                    .withHeight (30);
    return font;
}

static const Font& getApplicationFont<FontStyle::paragraph>()
{
    static Font font { "Helvetica" }.withHeight (18);
    return font;
}

Hopefully that helps?

1 Like

Thanks for the detailed reply,

You are right, composition is better, but I have 2 reason to derive it,
First one is, I just want to regex replace of class names of declarations instead of adding

.withStyle (Font::bold)

Second and my main reason is I have a layered project that has a GUI layer derives most of JUCE components to abstract JUCE api. So I can replace the JUCE api with other in the future easly. I thought having a general font customization class in my GUI layer could be better. But as you said and I just noticed juce::Font doesnt have any virtual. I’ll try your methods, thanks.