Managing Virtual Methods: 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).

Lambda Functions

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.158.134