virtual class

185 views
Skip to first unread message

wei zhang

unread,
Jun 20, 2017, 4:48:40 AM6/20/17
to ISO C++ Standard - Future Proposals
I suggest a virtual class declaration that it can only be inherited with virtual keyword.

Sample

virtual class BaseObject{
public:
   
void * GetBasePtr(){return this;};
protected:
   
int my_value;
};
    


You must virtual inherits this class otherwise compile will report error.  
Sample:
class MyClass:public virtual BaseObject
{
 
...
}

The MyClass will compile error without the virtual keyword.

With this restriction, architecture programmer can restrict that his Base Class won't have poly-inherit problem.


You can also combine virtual with abstract.  So like
virtual abstract class BaseObject{
...
};




Daniel Krügler

unread,
Jun 20, 2017, 5:03:09 AM6/20/17
to std-pr...@isocpp.org
2017-06-20 10:48 GMT+02:00 wei zhang <lala.wi...@gmail.com>:
> I suggest a virtual class declaration that it can only be inherited with
> virtual keyword.
>
> Sample
>
> virtual class BaseObject{
> public:
> void * GetBasePtr(){return this;};
> protected:
> int my_value;
> };
>
>
>
> You must virtual inherits this class otherwise compile will report error.
>
> Sample:
> class MyClass:public virtual BaseObject
> {
> ...
> }
>
> The MyClass will compile error without the virtual keyword.

So you intend to break *all* existing C++ code in the world that
currently uses virtual inheritance?

I guess the chances for the acceptance of such a proposal is close to zero.

- Daniel

Michał Dominiak

unread,
Jun 20, 2017, 5:07:47 AM6/20/17
to std-pr...@isocpp.org
No, he doesn't want to change virtual inheritance, he wants to introduce a new thing that can only be inherited virtually. I don't think this would be a breaking change in any way, but that doesn't change the fact that virtual inheritance is funky enough to be avoided in almost all cases (unless you're an expert, but an expert knows when to break the rule); this would only lead to virtual inheritance and spaghetti class hierarchies spreading.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAGNvRgB8aJU%3Dx42whgOc0guic-UKWWf9%3Dh%3Dxic31cT8R1Eg5hQ%40mail.gmail.com.

Ricardo Fabiano de Andrade

unread,
Jun 20, 2017, 11:36:57 AM6/20/17
to std-pr...@isocpp.org
What to say about final and override then?
Do they lead to more use of bad dynamic polymorphism or just make it less error prone?
Any idea that prevents mistakes should be welcome.

On Tue, Jun 20, 2017 at 4:07 AM, Michał Dominiak <gri...@griwes.info> wrote:
No, he doesn't want to change virtual inheritance, he wants to introduce a new thing that can only be inherited virtually. I don't think this would be a breaking change in any way, but that doesn't change the fact that virtual inheritance is funky enough to be avoided in almost all cases (unless you're an expert, but an expert knows when to break the rule); this would only lead to virtual inheritance and spaghetti class hierarchies spreading.

On Tue, Jun 20, 2017 at 11:03 AM Daniel Krügler <daniel....@gmail.com> wrote:
2017-06-20 10:48 GMT+02:00 wei zhang <lala.wi...@gmail.com>:
> I suggest a virtual class declaration that it can only be inherited with
> virtual keyword.
>
> Sample
>
> virtual class BaseObject{
> public:
>     void * GetBasePtr(){return this;};
> protected:
>     int my_value;
> };
>
>
>
> You must virtual inherits this class otherwise compile will report error.
>
> Sample:
> class MyClass:public virtual BaseObject
> {
>   ...
> }
>
> The MyClass will compile error without the virtual keyword.

So you intend to break *all* existing C++ code in the world that
currently uses virtual inheritance?

I guess the chances for the acceptance of such a proposal is close to zero.

- Daniel


--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

Nicol Bolas

unread,
Jun 20, 2017, 11:54:08 AM6/20/17
to ISO C++ Standard - Future Proposals
On Tuesday, June 20, 2017 at 11:36:57 AM UTC-4, Ricardo Andrade wrote:
What to say about final and override then?
Do they lead to more use of bad dynamic polymorphism or just make it less error prone?
Any idea that prevents mistakes should be welcome.

`override` merely prevents mistakes. The cases where `override` would cause a compile error are cases where the user's declared intent does not match the function signature they have written. You intend to override a function, but there is no matching signature to be override. That's clearly a mistake.

This notion of `virtual` "prevents mistakes" only if you start from the belief that all non-virtual inheritance is a mistake. But this belief is decidedly nonsensical.

Please provide a demonstration of a class that must be virtually inherited in all places where it gets used as a base class. Where all non-virtual inheritance of such a class would be as clear a mistake as those caught by `override`.

You could suggest a "lighter" version of this `virtual class` notion, where you only get a compile error if there are multiple, non-virtual inheritances of the same base class. However, I would again like to see a base class where, by the nature of that base class, this would always be a problem.

Ricardo Fabiano de Andrade

unread,
Jun 20, 2017, 2:12:43 PM6/20/17
to std-pr...@isocpp.org
I found interesting that you focused on `override` and mentioned nothing about `final` which would much closer to the suggested `virtual` since it applies to classes.
If I understood the OP correctly, `virtual` would be used for base classes that due some design decision it's known ahead of time that it will fall into the diamond problem of multiple inheritance and virtual inheritance must be used on the derived classes.
The annotation as `virtual` triggering a compiler error in this case could be beneficial to the users of such base class.

In the same line, someone only uses `final` when the class should never be used as a base class due some design decision.
So I can't provide such the demonstration you're requesting for `virtual` as one would not be able to provide one `final` for all its uses.

It's a design decision based on the problem at hand.
And if the design decision around multiple inheritance is bad or good, that's besides the point.


--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Tony V E

unread,
Jun 20, 2017, 2:19:41 PM6/20/17
to Ricardo Fabiano de Andrade
So, for final, there were motivating examples of classes that shouldn't be derived from. 

What are the motivating examples of classes that should only be virtually derived from?

I think they exist, I may have even written some, but they need to be shown. As 'real world' as possible. Not theoretical.

Sent from my BlackBerry portable Babbage Device
From: Ricardo Fabiano de Andrade
Sent: Tuesday, June 20, 2017 2:12 PM
Subject: Re: [std-proposals] virtual class

To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

Matt Calabrese

unread,
Jun 20, 2017, 2:27:32 PM6/20/17
to ISO C++ Standard - Future Proposals
On Tue, Jun 20, 2017 at 11:54 AM, Nicol Bolas <jmck...@gmail.com> wrote:
Please provide a demonstration of a class that must be virtually inherited in all places where it gets used as a base class. Where all non-virtual inheritance of such a class would be as clear a mistake as those caught by `override`.

I'm not voicing whether I think this feature is useful or not, but the common example types that are often argued "should" always use virtual inheritance are tag-dispatch types and exception base classes, and the rationale is solid (dispatching in the tag-dispatch case and catching in the exception case shouldn't be ambiguous via duplicate bases). That said, not all people buy into with that rationale and also if you know your whole program and all concepts/exceptions involved, you can avoid the virtual inheritance.

Nicol Bolas

unread,
Jun 20, 2017, 4:21:36 PM6/20/17
to ISO C++ Standard - Future Proposals
On Tuesday, June 20, 2017 at 2:12:43 PM UTC-4, Ricardo Andrade wrote:
I found interesting that you focused on `override` and mentioned nothing about `final` which would much closer to the suggested `virtual` since it applies to classes.
If I understood the OP correctly, `virtual` would be used for base classes that due some design decision it's known ahead of time that it will fall into the diamond problem of multiple inheritance and virtual inheritance must be used on the derived classes.
The annotation as `virtual` triggering a compiler error in this case could be beneficial to the users of such base class.

In the same line, someone only uses `final` when the class should never be used as a base class due some design decision.
So I can't provide such the demonstration you're requesting for `virtual` as one would not be able to provide one `final` for all its uses.

Which is exactly why I didn't mention class `final`: because I don't think that we really needed that one either.

Function `final` means something: that any attempt to override that function should fail. But class `final` represents the class writer trying to demand something of the user that a user shouldn't have to accept: how to use that class as a base class (or rather, that you can't).

Deriving from a class in C++ means something different from other languages; that's why multiple inheritance is not a bug in C++. It is a perfectly legitimate mechanism for performing various actions, not all of which involve overriding functions.

There's a reason why `vector` is not `final`. Nor is any other standard library type; indeed, the standard expressly says that all types are non-`final` unless otherwise noted. It is a pointless restriction on the user's ability to use a type.

The same goes for this `virtual` keyword. If you cannot write a class for which `virtual` inheritance is essential in all base class instances, then you have no right to declare that a user must virtually inherit from it in all base class instances.

If there is going to be a restriction, then the restriction ought to be that, if a type inherits from this type more than once in the same inheritance graph, then it must be declared `virtual` at all cites of inheritance.

It's a design decision based on the problem at hand.
And if the design decision around multiple inheritance is bad or good, that's besides the point.

Matt Calabrese mentioned a possible example: exception base class types. And this example, to me, shows exactly why this is wrong-headed. It's all a matter of what the syntax is saying.

To declare that a class requires virtual inheritance as a base class is to make a strong statement about that class. You're saying that the class is non-functional if you don't virtually inherit from it. If the idea is merely that you might use it wrong, then it shouldn't be there.

`override` is OK because it expresses the user's intent more directly. `virtual` alone isn't enough to make sure the compiler understands the difference between "I'm declaring a new `virtual` function" and "I'm overriding an existing `virtual` function."

What you're talking about is entirely different. It's not about the user of a class declaring their intent more fully. It's about the writer of a class preemptively stopping you from doing something that might cause a problem.

I don't like the idea of adding syntax to the language that forces people to use a non-optimal construct just because they might misuse it. Remember: virtual inheritance isn't free. It's like making a construct that forces all derived classes to declare all their functions `virtual`, just because they might not do so in the cases that need it.
Message has been deleted

wei zhang

unread,
Jun 21, 2017, 12:05:50 AM6/21/17
to ISO C++ Standard - Future Proposals
The reason we must force programmer to virtual inherits a base class is that
The object system (or alike) requires that.  In game programming, we need to manage a lot of objects.  Normally we would provide a BaseObject class that would record basic informations like objId or other things.  However,  if a user inherit the BaseObject accidently like polymorph style,  the object manager will goes faulty.  So that the system requires the BaseObject be virtual for anyone want to register the newed object into it.
Without the virtual keyword.  We still can require the same thing. it would be like

class VirtualObject {
   
int objid; 
   
...
}
class BaseObject:public virtual VirtualObject
{
   
// normally there's nothing
}

But first, it forces virtual without a noticeable thing when user inherits BaseObject.
Second, the functional class is VirtualObject, but user need to inherits BaseObject.  
Third, you cannot forbid user  inheirting VirtualObject directly.

在 2017年6月20日星期二 UTC+8下午4:48:40,wei zhang写道:

Nicol Bolas

unread,
Jun 21, 2017, 9:40:52 AM6/21/17
to ISO C++ Standard - Future Proposals
On Wednesday, June 21, 2017 at 12:05:50 AM UTC-4, wei zhang wrote:
The reason we must force programmer to virtual inherits a base class is that
The object system (or alike) requires that.  In game programming, we need to manage a lot of objects.

And in game programming, you would normally avoid virtual inheritance like the plague. At least, you'd avoid it for any object that's going to be used in a hot loop.
 
Normally we would provide a BaseObject class that would record basic informations like objId or other things.  However,  if a user inherit the BaseObject accidently like polymorph style,  the object manager will goes faulty.  So that the system requires the BaseObject be virtual for anyone want to register the newed object into it.

From what you said, it doesn't require that it use virtual inheritance at all. It merely requires that virtual inheritance be used if and only if you include the same base class from two different sources. There's a difference between forcing someone to use a technique when not using it would be broken, and forcing someone to use a technique even when not using it wouldn't be broken.

Why should a user be prevented from deriving non-virtually from BaseObject, when they know it will be completely safe for them? Why do you want to prevent users from writing perfectly valid, reasonable, functional, and performant code?

C++ is not Java; we do not preemptively make people's code slower just because they might misuse something.

That's why I say the feature should be `unique`: if this class appears in a class's list of base classes, it shall either appear exactly once or it shall be virtually inherited in all places where it does appear. It therefore ensures unambiguous conversion of `T` into `BaseClass`.

It would also fit better syntactically with class `final`, since it could just be another special identifier:

class BaseObject unique
{
};

FrankHB1989

unread,
Jun 29, 2017, 10:26:08 PM6/29/17
to ISO C++ Standard - Future Proposals


在 2017年6月21日星期三 UTC+8上午4:21:36,Nicol Bolas写道:
On Tuesday, June 20, 2017 at 2:12:43 PM UTC-4, Ricardo Andrade wrote:
I found interesting that you focused on `override` and mentioned nothing about `final` which would much closer to the suggested `virtual` since it applies to classes.
If I understood the OP correctly, `virtual` would be used for base classes that due some design decision it's known ahead of time that it will fall into the diamond problem of multiple inheritance and virtual inheritance must be used on the derived classes.
The annotation as `virtual` triggering a compiler error in this case could be beneficial to the users of such base class.

In the same line, someone only uses `final` when the class should never be used as a base class due some design decision.
So I can't provide such the demonstration you're requesting for `virtual` as one would not be able to provide one `final` for all its uses.

Which is exactly why I didn't mention class `final`: because I don't think that we really needed that one either.

Function `final` means something: that any attempt to override that function should fail. But class `final` represents the class writer trying to demand something of the user that a user shouldn't have to accept: how to use that class as a base class (or rather, that you can't).

Then you'd reject qualifiers and `constexpr`, similarly. They do introduce restrictions to allow some code patterns hardly existed in a language lack of them.

For example, if you don't have explicit `final` annotation in the class definitions, you have to rely on automatic devirtualization to achieve same effect. Similarly, if you don't have qualifiers in the type system, you have to rely on qualifier inference to achieve parts of the same effect. If you don't have explicit `constexpr` to inform the implementation of constant expressions in general, you have to rely on general partial evaluation. The point is, at least for C++, all of are very difficult to implement (if not impossible) with enough availability in reality, without aid of explicit annotation in the core language; and explicit notation also lead to saner interface and more readable code (hopefully). So if not standardized, users' may never have possibilities to use them in real world, with any dialects provided, even they have quite clear and reasonable needs. Note there are differences among these features (e.g. whether they have effects only on observable behavior of the programs), but they don't invalidate the point.

On the other hand,  `final` is perfectly appropriate in cases where the classes in the hierarchy are all internal implementation details, rather than as parts of public interface. (This should be at least already popular in contemporary standard library implementations.) For the reasons you mentioned, I'm not sure current `final` is only appropriate for such cases, but if the `final` is specified only having effect on public inheritance, it would be more acceptable, though adding `final` in the standard library massively can break currently well-defined program (e.g. my code has used inheritance of `u16string`, as a hack for mixin).

Deriving from a class in C++ means something different from other languages; that's why multiple inheritance is not a bug in C++. It is a perfectly legitimate mechanism for performing various actions, not all of which involve overriding functions.

There's a reason why `vector` is not `final`. Nor is any other standard library type; indeed, the standard expressly says that all types are non-`final` unless otherwise noted. It is a pointless restriction on the user's ability to use a type.

The same goes for this `virtual` keyword. If you cannot write a class for which `virtual` inheritance is essential in all base class instances, then you have no right to declare that a user must virtually inherit from it in all base class instances.

If there is going to be a restriction, then the restriction ought to be that, if a type inherits from this type more than once in the same inheritance graph, then it must be declared `virtual` at all cites of inheritance.

What if this is violated? UB? Or something other that cannot be possibly implemented in general?

It's a design decision based on the problem at hand.
And if the design decision around multiple inheritance is bad or good, that's besides the point.

Matt Calabrese mentioned a possible example: exception base class types. And this example, to me, shows exactly why this is wrong-headed. It's all a matter of what the syntax is saying.

To declare that a class requires virtual inheritance as a base class is to make a strong statement about that class. You're saying that the class is non-functional if you don't virtually inherit from it. If the idea is merely that you might use it wrong, then it shouldn't be there.

No.

It is true that the restrictions should only be right in quite limited cases. But also importantly, lack of them would cause real problems.

For exception base classes as parts of public interface (esp. for which are intended as base classes), missing `virtual` before the base-specifier is almost certainly a mistake, not only "might". It is regrettable that std::exception is inherited non-virtually in the standard library, which have already cause problems on NIH/ABI compatibility vs. overhead, etc. (Why boost::exception?)

For tag dispatching types, mandatory `virtual` reduces mistakes, and can be the only intentional way for some bases. However there is one more problem: I have no luck about bloated code without hacking on the implementation (and this is still not resolved). Note all the inheritance is known during translation and no RTTI is expected, so no runtime metadata (vtable-like stuff) is needed. So I want some more attributes here, not only the proposed `virtual`. Note that, even if with only this `virtual`, the implementation would be already able to optimize (theoretically), with expense of altering to new ABI in generated code, which is totally insane (breaking compatiblity) if something like `virtual` here is not exist.

Nicol Bolas

unread,
Jun 30, 2017, 11:13:40 AM6/30/17
to ISO C++ Standard - Future Proposals
On Thursday, June 29, 2017 at 10:26:08 PM UTC-4, FrankHB1989 wrote:
在 2017年6月21日星期三 UTC+8上午4:21:36,Nicol Bolas写道:
On Tuesday, June 20, 2017 at 2:12:43 PM UTC-4, Ricardo Andrade wrote:
I found interesting that you focused on `override` and mentioned nothing about `final` which would much closer to the suggested `virtual` since it applies to classes.
If I understood the OP correctly, `virtual` would be used for base classes that due some design decision it's known ahead of time that it will fall into the diamond problem of multiple inheritance and virtual inheritance must be used on the derived classes.
The annotation as `virtual` triggering a compiler error in this case could be beneficial to the users of such base class.

In the same line, someone only uses `final` when the class should never be used as a base class due some design decision.
So I can't provide such the demonstration you're requesting for `virtual` as one would not be able to provide one `final` for all its uses.

Which is exactly why I didn't mention class `final`: because I don't think that we really needed that one either.

Function `final` means something: that any attempt to override that function should fail. But class `final` represents the class writer trying to demand something of the user that a user shouldn't have to accept: how to use that class as a base class (or rather, that you can't).

Then you'd reject qualifiers and `constexpr`, similarly. They do introduce restrictions to allow some code patterns hardly existed in a language lack of them.

Where's this strawman coming from?

`constexpr` has a purpose: it makes it possible to call a function in a constant-expression context. It's functionality that comes with restrictions, not a pure-restriction.

Class-scoped `final` does not make the class better; it makes it less useful.

For example, if you don't have explicit `final` annotation in the class definitions, you have to rely on automatic devirtualization to achieve same effect.

Nonsense. If you annotate every virtual function with `final`, then you achieve the same devirtualization effect. That's why I say that class-`final` ought to do only that; it shouldn't stop you from deriving from the class.

Similarly, if you don't have qualifiers in the type system, you have to rely on qualifier inference to achieve parts of the same effect. If you don't have explicit `constexpr` to inform the implementation of constant expressions in general, you have to rely on general partial evaluation. The point is, at least for C++, all of are very difficult to implement (if not impossible) with enough availability in reality, without aid of explicit annotation in the core language; and explicit notation also lead to saner interface and more readable code (hopefully). So if not standardized, users' may never have possibilities to use them in real world, with any dialects provided, even they have quite clear and reasonable needs. Note there are differences among these features (e.g. whether they have effects only on observable behavior of the programs), but they don't invalidate the point.

On the other hand,  `final` is perfectly appropriate in cases where the classes in the hierarchy are all internal implementation details, rather than as parts of public interface.

If a class is not part of the public interface, then the user using it at all is a problem; it's a violation of the interface contract. Class-`final` doesn't prevent people from using it; it only stops them from using it in one very specific way. So it's hardly a solution.

But this is an issue that will become increasingly less important. With modules, users won't even have access to the names (unless they use reflection to access them).

(This should be at least already popular in contemporary standard library implementations.) For the reasons you mentioned, I'm not sure current `final` is only appropriate for such cases, but if the `final` is specified only having effect on public inheritance, it would be more acceptable, though adding `final` in the standard library massively can break currently well-defined program (e.g. my code has used inheritance of `u16string`, as a hack for mixin).

Deriving from a class in C++ means something different from other languages; that's why multiple inheritance is not a bug in C++. It is a perfectly legitimate mechanism for performing various actions, not all of which involve overriding functions.

There's a reason why `vector` is not `final`. Nor is any other standard library type; indeed, the standard expressly says that all types are non-`final` unless otherwise noted. It is a pointless restriction on the user's ability to use a type.

The same goes for this `virtual` keyword. If you cannot write a class for which `virtual` inheritance is essential in all base class instances, then you have no right to declare that a user must virtually inherit from it in all base class instances.

If there is going to be a restriction, then the restriction ought to be that, if a type inherits from this type more than once in the same inheritance graph, then it must be declared `virtual` at all cites of inheritance.

What if this is violated? UB? Or something other that cannot be possibly implemented in general?

"must" in spec-speak, when applied to what users can do, usually means "ill-formed if you don't do it". This is something the compiler is perfectly capable of detecting.

It's a design decision based on the problem at hand.
And if the design decision around multiple inheritance is bad or good, that's besides the point.

Matt Calabrese mentioned a possible example: exception base class types. And this example, to me, shows exactly why this is wrong-headed. It's all a matter of what the syntax is saying.

To declare that a class requires virtual inheritance as a base class is to make a strong statement about that class. You're saying that the class is non-functional if you don't virtually inherit from it. If the idea is merely that you might use it wrong, then it shouldn't be there.

No.

It is true that the restrictions should only be right in quite limited cases. But also importantly, lack of them would cause real problems.

For exception base classes as parts of public interface (esp. for which are intended as base classes), missing `virtual` before the base-specifier is almost certainly a mistake, not only "might". It is regrettable that std::exception is inherited non-virtually in the standard library, which have already cause problems on NIH/ABI compatibility vs. overhead, etc. (Why boost::exception?)
For tag dispatching types, mandatory `virtual` reduces mistakes, and can be the only intentional way for some bases. However there is one more problem: I have no luck about bloated code without hacking on the implementation (and this is still not resolved). Note all the inheritance is known during translation and no RTTI is expected, so no runtime metadata (vtable-like stuff) is needed. So I want some more attributes here, not only the proposed `virtual`. Note that, even if with only this `virtual`, the implementation would be already able to optimize (theoretically), with expense of altering to new ABI in generated code, which is totally insane (breaking compatiblity) if something like `virtual` here is not exist.

Alternatively, you can just use type-lists and metaprogramming techniques based on such things. Type-lists can be concatenated (even with duplicates), so you can create "hierarchies" of such things. You can constexpr query whether a type-list contains a member of a certain type, and use SFINAE based on that. Or Concepts/`if constexpr`; whichever works for you.
Reply all
Reply to author
Forward
0 new messages