Contextual Keywords

I believe the C++ standards committee got some things wrong in the distant past. Converting constructors work implicitly with an assignment operation, function hiding and overriding are not explicit, there’s no way to prevent a subclass from providing further overrides to virtual functions, etc. But with the new C++11, I believe they are trying to make amends. I want to discuss some of the new contextual keywords in the latest version of C++.
There are four contextual keywords that have been added to C++ which relate to subclassing: new, explicit, final, and override. In earlier versions of the draft specification, these were actually attributes supported by the compiler (and went by somewhat different names). But they’ve been promoted to first-class language features due in large part to their importance in writing explicit, verifiably correct code.

As I mentioned, these keywords are contextual. You can still use final and override as identifiers in your code (though I wouldn’t suggest it), and explicit and new still function in their usual ways. The final and override keywords are all placed at the end of a class instance method declaration. The new keyword is placed at the end of class method declarations as well as variable declarations. The explicit keyword is placed in the class declaration. The basic idea behind these keywords is:

The override keyword means “this class is overriding the virtual function declared in the base class.”

The new keyword means “this member is hiding a named member from a base class.”

The explicit keyword means “all of the declarations in this class will use the override and new specifiers as needed, or else it will generate errors.”

One thing to remember is that even if something could qualify for two contextual keywords (such as override and final), only one contextual keyword is allowed. This really is only an issue for override and final where the declaration could make sense for both keywords, but in this case, final is the appropriate keyword to use as it implies an override.

final

In some circumstances, a class will override a function from a base class in such a way that further derived classes should not override it. This is the situation for which the final keyword was created. When you specify a method as being final, any attempts to override the function (either explicitly with the override keyword, or implicitly) will cause a compile error. For instance:

The Base class defines a virtual method to state whether the class is “awesome” or not. The Awesome subclass answers that question. However, any further subclasses from Awesome should not have a different answer to the IsAwesome question. So the Awesome subclass marks the IsAwesome function as being final, thus preventing a potential cause for bugs.

override

The override keyword tells the compiler your intentions in a more explicit manner. Obviously it’s not neccessary in order for overriding to work, but the problem is that the rules for overriding can be complicated. You can use covariant return types or polymorphic parameters, and the slightest mistake means that your function isn’t going to be called as you might expect. By using the override keyword, the compiler can verify that you intend to override a function from the base class, and if there is no valid override, the compiler can produce an error. For instance:

Did you spot the bug? These sort of mistakes are very easy for our eyes to “skip over” when trying to debug code. The problem is that Base::DoSomething isn’t virtual, so the Derived::DoSomething cannot override it!

new

The new keyword is a way for you to safely hide names from the base class from within the derived subclass. While I personally don’t recommend hiding names (I find it to be confusing), being able to tell the compiler your intentions can prevent problems in complex source bases. For instance:

In this case, the class Derived is hiding the name of the member variable Data from Base. If there is a caller from within Derived that wants to access the Base::Data variable, they’ll be in for a nasty surprise as it will look like a function call unless they are explicit about their access. Additionally, if Derived::Base really did not hide anything named Data, the compiler has the opportunity to bark at the programmer. This can be handy when doing refactoring projects as there may be further code that can be removed (such as explicit named lookups). However, the true power of the new keyword (at least, to me) comes from the next topic.

explicit

The explicit keyword allows you to specify that all declarations within the class will properly mark whether it’s an override or a new declaration. If the compiler finds something which accidentally overrides when you don’t expect it, or accidentally hides when you don’t expect it, then it can generate an error to let you know. This is an incredibly powerful tool for object-oriented programming as it means you can have more confidence with your declarations. For instance:

As you can see, by being explicit with your intentions, the compiler can provide you with more assistance for dangerous situations you may not have been aware you were in. What’s more, it signals your intentions to other programmers who have to read or maintain your code. For instance, when someone sees the override keyword, they don’t need to delve through the class hierarchy to learn that the function comes from a base class. Or when they see the new keyword, they can be more careful about how they access the member.

tl;dr: in order to ensure you broadcast your intentions properly, I would highly recommend using the explicit keyword when declaring a class, and using the overrides and new keywords as appropriate. It makes your code safer and more clear.

Update 9/19/11: I finally got my hands on the FDIS C++11 spec, and it turns out they removed support for the new and explicit contextual keywords between the version I had (Feb 2011) and the final (Sept 2011). So the parts where I talk about new and explicit are not valid (but will hopefully become valid for the next version of C++, because I really love the concept!).

Your email address will not be published. Required fields are marked *

Comment

Name *

Email *

Website

Who

Aaron Ballman is a software engineer for GrammaTech. He has almost two decades of experience writing cross-platform frameworks in C/C++, compiler & language design, and software engineering best practices and is currently a voting member of the C (WG14) and C++ (WG21) standards committees.

In case you can't figure it out easily enough, the views expressed here are my personal views and not the views of my employer, my past employers, my future employers, or some random person on the street. Please yell only at me if you disagree with what you read.