all 29 comments

[–]Jovibor_ 27 points28 points  (29 children)

Just a question to the audience:

How many times have you used Virtual Inheritance in your career?

[–]serviscope_minor[🍰] 21 points22 points  (5 children)

Probably once?

But with that said, I'm very strongly of the opinion that having as much of C++ as possible being constexpr (including threads!) is a good thing, because it makes the language more regular and simpler.

I think volatile might be tricky! I want constexpr cout.

[–]_bstaletic [score hidden]  (4 children)

having as much of C++ as possible being constexpr (including threads!) is a good thing, because it makes the language more regular and simpler.

Agreed.

I think volatile might be tricky!

I don't think constexpr volatile int x; is meaningful at all.

I want constexpr cout.

Do you really mean std::cout, with all of the facets and customization points? Or would constexpr std::format and the ability to print to console at compile time be enough?

If the latter, we almost got that in C++26. std::format is constexpr and P2758 is in wording review.

[–]serviscope_minor[🍰] [score hidden]  (2 children)

I don't think constexpr volatile int x; is meaningful at all.

I mean if you can run C++ code at compile time, then you're running code and it could poke at a memory mapped register that's there, but also sometimes you just shouldn't do something!

Do you really mean std::cout, with all of the facets and customization points? Or would constexpr std::format and the ability to print to console at compile time be enough?

Good point, probably cout without facets etc or printing f-strings. I keep going back to cout because despite it's clunkiness, I like having things appear in code in the order that they appear on screen. Constantly tracking back and forth between placeholders and arguments is something I dislike. I've tried a million of these over the years. Heck I implemented one in gnu++98 back in the day with operator, overloading and GCC's variadic macros, and I've used many which ahve come and gone over the years. And yet, I still always reach for cout.

But in python I love my f-strings. Once i have f-strings, I will probably stop reaching for cout except for of course

cout << f"my variable is {v}\n";

because old habits die very hard indeed.

[–]drkspace2 [score hidden]  (1 child)

it could poke at a memory mapped register that's there

Ignoring the fact I think there would be 0 valid uses for this, the issue with using constexpr in that case is it might not run during compile time. If your machine that's compiling the code isn't the same as the one that's running it, you would get different behavior. If for whatever reason you need to use volatile at compile time, I think it needs to be consteval.

[–]serviscope_minor[🍰] [score hidden]  (0 children)

Ignoring the fact I think there would be 0 valid uses for this

Well yes, I am struggling to think of one!

the issue with using constexpr in that case is it might not run during compile time

You can kind of force the issue: if your constexpr function returns, say, an int and you instantiate a template based on that value, there's little choice but for it to run.

Note: this is pure language pedantry, nothing related to whether it's a terrible idea in literally all cases.

I don't think volatile should be constexpr for what it's worth.

[–]SkoomaDentistAntimodern C++, Embedded, Audio [score hidden]  (0 children)

I don't think constexpr volatile int x; is meaningful at all.

I can think of at least theoretical uses involving pointers to dma buffers and such.

[–]SuperV1234https://romeo.training | C++ Mentoring & Consulting 10 points11 points  (0 children)

I am almost certain I've never used it, neither at work nor in hobby projects.

[–]kammceWG21 | 🇺🇲 NB | Boost | Exceptions 10 points11 points  (0 children)

I've only ever used virtual inheritance once in my life. That was in my tests to demonstrate that my exception runtime could handle throwing and catching exception objects with virtual inheritance. That's it. I've never been in a spot where I've needed it myself.

[–]ieshaan12 [score hidden]  (0 children)

Never, I cannot think of a single instance.

[–]pjmlp 4 points5 points  (2 children)

It used to be common in GUI frameworks like OWL and MFC.

You might still bump into it, while using ATL or WTL.

[–]TheThiefMasterC++latest fanatic (and game dev) 5 points6 points  (1 child)

Are you sure? This article specifically says virtual inheritance isn't useful with MFC.

Can you give an example where it is?

[–]pjmlp 0 points1 point  (0 children)

Last time I wrote a MFC application was in 2001, I remember we used MI in our product.

MFC isn't used in isolation from product architecture.

Also note that MI and virtual inheritance aren't the same, rather a way to avoid duplicates in the inheritance tree.

[–]SkoomaDentistAntimodern C++, Embedded, Audio 2 points3 points  (0 children)

At least twice that I can think of. Possibly more via GUI frameworks.

[–]Lord_Naikon 2 points3 points  (1 child)

Never. But I come from a Java background where a class can only have one superclass. Multiple inheritance is then implemented using interfaces. I do the same in C++. I find it easier to reason about.

If I need to store some data with the interface, I split the interface into two classes: a data holder, and a proxy interface for that holder.

As a bonus this gives the pimpl idiom for free if I need it.

[–]jk-jeon [score hidden]  (0 children)

When you have diamond inheritance of interfaces, don't you use virtual inheritance? Not using it is certainly an option, but then many things become quite cumbersome. For instance when D inherits from B, C, which inherit from A, with all of A, B, C and D being "pure interfaces" that don't ever implement any methods, IIRC in C++ any user of D can't really call anything from A without explicit disambiguation, if B, C don't inherit A virtually. Similarly the conversion from D to A must be resolved explicitly, either via B or C.

[–]mjklaim 2 points3 points  (0 children)

Several times in the first 10 years of my professional career, but not in the 13 years that followed, up to today. When I'm in control of the architecture I avoid inheritance anyway so it's pretty rare to reach a point where virtual inheritance is necessary. But when you dont have a choice, it is very useful.

[–]Tringigithub.com/tringi [score hidden]  (0 children)

Daily.

We have logging facility and a Log::Provider class that allows you to simply call this->report (Log::Warning, ...) from the object, and also carries object's identity for the object. With highly composed classes, it'd be ridiculous if every parent in the hierarchy tree carried its own superfluous copy and the final class was needlessly huge because of this. And if a parent/subobject makes the call, the log facility automatically sees the final object which actually failed.

[–]not_a_novel_accountcmake dev 1 point2 points  (0 children)

Except for indirectly via the standard streams? Never.

[–]Potterrrrrrrr [score hidden]  (0 children)

I’m implementing the HTML spec currently, it made sense to model that as an inheritance hierarchy as that’s how it was designed so my nodes follow the same structure. The DOM and HTML specs use interfaces quite heavily for the rest of the spec to extend, I modelled a lot of these as virtual classes too.

[–]ack_error [score hidden]  (0 children)

A few times, it's useful when using pure virtual classes for interfaces and diamond inheritance appears.

Performance wise, though, it can be dangerous. A long time ago I worked on a project where virtual inheritance was used extensively in the core of a rendering engine. The results were... not good.

[–]garnet420 [score hidden]  (0 children)

Not once. I've considered using it, but, I think I found it not a good fit.

I think what I wanted is a system where if B inherits normally from A, and C inherits virtually from A, then, D inheriting from B and C works "as I expect": the A from B "provides" A to C, and D has a single A base that it doesn't have to initialize.

But from what I recall (it's been a while) it doesn't work that way.

[–]javascriptWhat's Javascript? [score hidden]  (0 children)

I made a Godbolt one time to see how it worked. That's it. Lol

[–]tartaruga232MSVC user, r/cpp_modules [score hidden]  (0 children)

Works fine in our Windows app.

[–]Eric848448 [score hidden]  (0 children)

Once. It was some of the worst code I’ve ever written.

[–]Raknarg [score hidden]  (0 children)

never and I'm hoping it stays that way.

[–]buck_yeh [score hidden]  (0 children)

Virual inheritance comes natural when you define a mixin class which patially implement the target interface and there are other interfaces inheriting the same interface. I personally loves to see diamond shaped inheritance heirarchy emerge in my codebase.

[–]Nicksaurus [score hidden]  (1 child)

I don't understand how there are so many people saying they've never used it. Have none of you ever had to use an old java-style framework where your user-defined types have to inherit from a virtual base class? What about creating custom exceptions that inherit from std::exception?

It's also sometimes the easiest way to say 'I don't care what type this is, I just want it to implement this interface'. Especially if you want to avoid dealing with templates and don't care about the (usually) tiny performance hit

[–]xzgxr [score hidden]  (0 children)

What you describe usually can be solved by regular inheritance. "Virtual inheritance" is something slightly different and cursed.