I'm torn. The step from C to any c++ is big. Now if you want anybody to be able to use your code they need to be using c++ or you have to provide a C api anyway. On the other hand, manually implementing vtables is annoying. Ive been sticking to pure C and haven't been bothered enough to go back to any c++ yet (about 6 months on my current project). I mostly only miss templated containers so far.
It is more annoying to want to implement an optional function in a class and then have no simple way to check if that optional function is implemented in the object without, having to edit code that guards the call sites every time you add a derived class that implements it, or having to implement your own way of querying the object to know if it is supported.
I've never come across a situation where I wanted to do this. What would be a use case for optional class functions?
Well, it would not be a class in that case, but a use case would be anything that is modular where you want to support a new function, but do not require all of your implementors to use it. The best example of this is the VFS. Here is documentation for the Linux VFS:
https://www.kernel.org/doc/html/latest/filesystems/vfs.html
The vast majority of the function pointers in those structures are optional (even if not explicitly stated). To give a few common sense examples:
Then there are other options, like not supporting mmap, or not supporting creation/removal of subdirectories. That sounds absurd, but some FUSE filesystems, particularly those exporting a program’s statistics, don’t bother with either of those since they are not needed. I do not believe Linux sysfs allows users to make directories either.I could continue, but this gives a few examples of why you might want to have optional functionality in a class-like interface.
By the way, I mentioned setting things you do not implement to NULL. This is done simply by not specifying them when using the structure initializer syntax. The compiler will zero unspecified members.
Nothing prevents implement something like that in C++, it is still C++ code.
If you want to make something fancy, templates, if constexpr requires func-to-call, call func.
The point of the throwaway account’s comment was to say that you should use C++ class member functions instead of C function pointers in structures, but that is impossible to do in the general case in a sane way, since there is no way to leave a member function unimplemented and then check its status at runtime.
You need to use hacks to shoehorn C++ class member functions into this. In particular, you need stub functions. Then either, call them and have them either return a special error code or throw an exception, or use a custom query function that is implemented by derived classes that lets you find out if a function is a stub or not to allow you to skip calling it. Another idea would be to use thread local storage with setjmp()/longjmp(), which is probably the sanest way of doing this insane idea:
https://godbolt.org/z/4GWdvsz6z
And the C way for comparison:
https://godbolt.org/z/qG3v5zcYc
The idea that the simplest way of approximating what you can do with function pointers in C structures via C++ class member functions is to use TLS and setjmp/longjmp shows what a bad idea it is to use class member functions instead of function pointers for optional functions in the first place.
C++ was designed as "Typescript for C" for its time, because sometimes that is exactly the kind of code one needs to write, even if we discourage many of the classical patterns when better alternatives exist.
The same C example compiled in C++23 mode, https://godbolt.org/z/MWa7qqrK7
As for possible alternatives, here is a basic one without taking into consideration virtual mechanics, only to show the principles.
-- https://godbolt.org/z/cjcbrzT3zNaturally it is possible to be a bit even more creative, and moreso with C++26 reflection.