That's also part of why I enjoy returning to c++, the people involved know how to structure code and create clean architecture.
That said, sometimes c++ does get in the way. Creating trees or graphs can be cumbersome, and IMO it's very biased towards virtual methods to solve polymorphism.
Extending lifetimes by pooling or similar is also quite common, and is in my eyes sometimes overdoing it. If you for instance use Rust, you can be a lot more confident that the compiler catches these issues, and be more conservative and efficient in the solution.
This is a function of the type of software you write. There are many large C++ code bases that rely on various types of static polymorphism almost exclusively, rarely having a use case for virtual methods or dynamic polymorphism. There is a similar story with inheritance versus composition; some types of code bases naturally gravitate toward one or the other.
The nice thing about C++ is that it as amenable to any of these models should it benefit the application.
So while it's there, I would say that the oo virtual method style is much better supported, although storage for those usually requires some type heap allocation.
I wasn't aware of this. Maybe I'm just out of the loop. Do you know where one can I learn more about this? I'm desperately trying to reduce the number of virtual calls in our codebase, but I'm hitting the aforementioned problems.
This has traditionally been managed with CRTP, tagged unions, etc with some scaffolding to make it convenient and compliant with strict aliasing rules. Ideally, almost all of the dynamic polymorphism is pulled up to the level of the page types, an opaque blob of I/O friendly complex data structure, minimizing the amount you have to do. It is also important to note that JIT-ing has replaced many of the use cases for dynamic dispatch e.g. adding user-defined schemas at runtime.
None of which may apply to your use case. Some things inherently require an unfortunate amount of dynamic dispatch.
Wouldn't Rust have the same problem with this (if not worse)?
Is it? These days I'd expect C++ to be very biased towards using templates for polymorphism. After all, templates are a thing that C++ provides with functionality that other languages often lack, whereas in the field of virtual methods/"dynamic dispatch OOP" C++ severely lags behind other languages. Choosing between two features of a language and using exactly the one that is worse in comparison to your competition feels wrong to me.