You may declare a function foo as a read-only function using readonly -f foo or declare -g -r -f foo (readonly is equivalent to declare -g -r). It's the -f option to these built-in utilities that makes them act on foo as the name of a function, rather than on the variable foo.
$ foo () { echo Hello; } $ readonly -f foo $ foo () { echo Bye; } bash: foo: readonly function $ unset -f foo bash: unset: foo: cannot unset: readonly function $ foo Hello
As you can see, making the function read-only not only protects it from getting overridden, but also protects it from being unset (removed completely).
Currently (as of bash-5.0.11), trying to modify a read-only function would not terminate the shell if one is using the errexit shell option (set -e). Chet, the bash maintainer, says that this is an oversight and that it will be changed with the next release.
Update: This was fixed during October 2019 for bash-5.1-alpha, so any bash release 5.1 or later would exit properly if an attempt to modify a read-only function is made while the errexit shell option is active.
typeset -r:typeset -rf f.readonly -f f