override
and final
Virtual methods are an important component of implementing polymorphic class hierarchies, in which a base class reference or pointer can invoke the particular method appropriate to the type of object referred to. Virtual methods do pose some programming pitfalls. For instance, suppose the base class declares a particular virtual method, and you decide to provide a different version for a derived class. This is called overriding the old version. But, as discussed in Chapter 13, “Class Inheritance,” if you mismatch the function signature, you hide rather than override the old version:
class Action
{
int a;
public:
Action(int i = 0) : a(i) {}
int val() const {return a;};
virtual void f(char ch) const { std::cout << val() << ch << "
";}
};
class Bingo : public Action
{
public:
Bingo(int i = 0) : Action(i) {}
virtual void f(char * ch) const { std::cout << val() << ch << "!
"; }
};
Because class Bingo
uses f(char * ch)
instead of f(char ch)
, f(char ch)
is hidden to a Bingo
object. This prevents a program from using code like the following:
Bingo b(10);
b.f('@'), // works for Action object, fails for Bingo object
With C++11, you can use the virtual specifier override
to indicate that you intend to override a virtual function. Place it after the parameter list. If your declaration does not match a base method, the compiler objects. Thus, the following version of Bingo::f()
would generate a compile-time error message:
virtual void f(char * ch) const override { std::cout << val()
<< ch << "!
"; }
For example, Microsoft Visual C++ 2010 has this to say:
method with override specifier 'override' did not override any
base class methods
The specifier final
addresses a different issue. You may find that you want to prohibit derived classes from overriding a particular virtual method. To do so, place final
after the parameter list. For example, the following code would prevent classes based on Action
to redefine the f()
function:
virtual void f(char ch) const final { std::cout << val() << ch << " ";}
The specifiers override
and final
do not quite have the status of keywords. Instead, they are labeled “identifiers with special meaning.” This means that the compiler uses the context in which they appear to decide if they have a special meaning. In other contexts, they can be used as ordinary identifiers (for example, as variable names or enumerations).
When you see the term lambda functions (a.k.a. lambda expressions or, simply, lambdas), you may suspect that this is not one of the C++11 additions intended to help the novice programmer. You will have your suspicions seemingly confirmed when you see how lambda functions actually look—here’s an example:
[&count](int x){count += (x % 13 == 0);}
But they aren’t as arcane as they may look, and they do provide a useful service, particularly with STL algorithms using function predicates.
18.119.158.134