Overriding Virtual Functions? Use C++0x Attributes to Avoid Bugs.

n July 2009, the C++ standards committee voted into the C++0x Working Paper new attribute tokens that regulate the overriding of virtual functions in a derived class. These new attributes ensure that an overriding function matches its base class counterpart by signature and name.

As trivial as it may seem, overriding a virtual member function can go wrong in many ways, most of which go undetected by the compiler. This 10-Minute Solution shows how to use the new C++0x attributes to avoid a few common bugs associated with overriding virtual functions.

While overriding a virtual function, you accidentally misspell the function’s name or inadvertently changed its parameter list. The compiler doesn’t catch these bugs.

Add the [[base_check]], [[hiding]], and [[override]] attributes to your derived classes. This will help the compiler catch errors that are otherwise undetectable.

Misspelled, Missed Error

Suppose you have a virtual function in a base class B and a derived class D that overrides that function:

struct B { virtual void func();};struct B: D { void func();};

C++ programmers assume that D::func() overrides B::func deliberately, but what if the programmer accidentally picks the name func() without noticing that D::func() overrides B::func()? The compiler can’t catch such accidental misnaming errors because the code is perfectly valid, even though it means something different from what the programmer intended.

Inadvertent overriding is fairly common. It occurs, for example, in projects where class libraries that contain hundreds of virtual functions are used. Two other problems occur even more frequently in class hierarchies:

  • Misspelled function names
  • Parameter mismatches

Let’s look at these two more closely.

Suppose you’re using a library that includes the following class:

struct Base { virtual void some_func1(); virtual void some_func2() const; virtual void some_func3(long);};

You want to derive a new class that will override the three member functions of Base. Unfortunately, you end up with code that does something quite different:

struct Derived: Base { void sone_func1(); //misspelled name, doesn't override void some_func2(); //cv-mismatch, hides Base::some_func2 void some_func3(long long); //parameter mismatch, hides Base::some_func3};

Notice that none of the three member functions of Derived actually overrides the corresponding member function of Base! What went wrong?

The function sone_func1() is misspelled. Instead of overriding Base::some_func1(), the compiler assumes that the programmer simply added a new function to Derived. So, some_func2() hides?rather than overrides?Base::some_func2(), because the two functions have incompatible cv-qualification.

Finally, Derived::some_func3() also hides Base::some_func3() because the parameter lists of the two functions don’t match.

Recall that implicit hiding is valid in C++. Some compilers issue a warning when a member function hides a base class name, while others don’t. The declaration of Derived thus compiles successfully, which makes these bugs much harder to detect, especially when an unsuspecting client uses code written by a third party.

Using Attributes

The compiler can’t guess the programmer’s intent. That is why misspelled function names and accidental hiding of base class functions go undetected. Three new C++0x attributes tackle this problem:

  • [[base_check]]: You use this attribute in a declaration of a derived class. It indicates that any name hiding or virtual function overriding within that class shall be marked with the appropriate attribute. Otherwise, a compilation error will occur.
  • [[override]]: This attribute applies to an overriding member function in a derived class. It indicates that a member function overrides a virtual function in a base class. If no appropriate virtual function is found, the program is ill formed.
  • [[hiding]]: This attribute indicates a member of a derived class that deliberately hides a member with the same name in a base class.

To “activate” the attributes [[override]] and [[hiding]], you first need to declare a derived class with the [[base_check]] attribute. Without [[base_check]], a derived class behaves as usual, allowing you to hide and override base class functions implicitly. A modified version of Derived looks like this:

struct Derived [[base_check]]: Base { void sone_func1 [[override]](); //error, spelling void some_func2 [[override]](); //error, signature void some_func3 [[override]](long long); //ditto};

Because the members of Derived are all declared [[override]], the compiler tries to match each one of them with a corresponding virtual function in the base class but fails. That leads to explicit compilation errors that tell the programmer exactly what’s wrong with the code.

Hide and Seek

You can add new functions to a derived class as well. A new function is indicated by the lack of any attributes:

struct Derived [[base_check]]: Base { int new_func(); //OK//...};

In some cases, hiding a name in a derived class makes sense. For that purpose, you have to use the [[hiding]] attribute:

struct Derived [[base_check]]: Base { void some_func1[[hiding]](double);//OK  void some_func2(short); //error, implicit hiding//...};

Implicit hiding in the class Derived isn’t allowed, because that class is declared [[base_check]]. Omitting [[base_check]] will switch off the compiler’s safeguards, reversing the validity of the functions’ declarations:

struct Derived : Base { void some_func1[[hiding]](double);//error,[[base_check]] required void some_func2(short); //OK, implicit hiding //...};

Attributes Are Your Friends

The attributes proposal drew criticism because some believed it was conceived as a mechanism for sneaking keywords into C++ and because many people don’t like the [[]] syntax. However, attributes are here to stay. They seem to solve a few annoying problems that previously had proved resistant to compilers.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin


The Latest

homes in the real estate industry

Exploring the Latest Tech Trends Impacting the Real Estate Industry

The real estate industry is changing thanks to the newest technological advancements. These new developments — from blockchain and AI to virtual reality and 3D printing — are poised to change how we buy and sell homes. Real estate brokers, buyers, sellers, wholesale real estate professionals, fix and flippers, and beyond may

man on floor with data

DevX Quick Guide to Data Ingestion

One of the biggest trends of the 21st century is the massive surge in internet usage. With major innovations such as smart technology, social media, and online shopping sites, the internet has become an essential part of everyday life for a large portion of the population. Due to this internet

payment via phone

7 Ways Technology Has Changed Traditional Payments

In today’s digital world, technology has changed how we make payments. From contactless cards to mobile wallets, it’s now easier to pay for goods and services without carrying cash or using a checkbook. This article will look at seven of the most significant ways technology has transformed traditional payment methods.