C++: Hide-by-name Semantics and Signatures

I’ve been using C++ for many years, yet there’s something fundamental that I’ve only just learned: It concerns something called hide-by-name semantics.

In my original code, I had STL containers, templates, template specialisation, and all sorts of other bits and pieces. When I reduced the problem to the basics, I was surprised by what I found to be the problem.

Here’s the code that wouldn’t compile, with the illegal line in red:

#include <iostream>
using namespace std;

class base
{
public:
    int arithmetic (int z) { return z * 2; }
};

class derived : public base
{
public:
    int arithmetic (int x, int y) { return x + y; }
};

int main (void)
{
    derived d;
    cout << d.arithmetic(1,2) << endl;
    cout << d.arithmetic(3) << endl;
        // error: 'derived::arithmetic' function does not take 1 argument 
    return 0;
}

[I have stripped out much that would be expected in code like this, such as virtual functions and a virtual destructor. As it happens, these were not required even in the original code, where I was just trying to endow a particular specialisation of an STL container class with an extended interface (there were no additional data members, and no overloaded function signatures).]

The problem is that, although the function arithmetic in the derived class has a different signature (a.k.a. extended name; i.e. the name together with the number, order and types of parameters; but not the return type) to that in the base class, the function in the derived class hides all functions with the same name in the base class. This is called “hide-by-name semantics” as compared to “hide-by-signature semantics”.

To be more precise, a function’s signature consists of:

  • the unqualified name
  • the namespace and class scope of that name
  • the const and/or volatile qualification of the function
  • the sequence of the function’s parameter(s):
    • number
    • order
    • types
  • if the name has internal (static) linkage:
    • the translation unit in which the name is declared
  • if the function is generated from a function template:
    • the template parameters and the template arguments
    • its return type

There are numerous solutions to the hiding problem.

The function required may be explicitly qualified on the call:

    cout << d.base::arithmetic(3) << endl;

The derived class could reimplement the base class functions (for all required signatures):

class derived : public base
{
public:
    int arithmetic (int z) { return base::arithmetic(z); } // re-implementation
    int arithmetic (int x, int y) { return x + y; }
};

The simplest solution may be to use a using statement (which makes all the base signatures available):

class derived : public base
{
public:
    using base::arithmetic; // to un-hide
    int arithmetic (int x, int y) { return x + y; }
};

Sometimes, the clearest solution may be to avoid the hiding by giving the new functions a different name:

class derived : public base
{
public:
    int further_arithmetic (int x, int y) { return x + y; }
};
	cout << d.further_arithmetic(1,2) << endl;
	cout << d.arithmetic(3) << endl;

Rather than explain any further, there are some web pages that discuss hide-by-name:

CodeGuru : “Here’s a little Object-Oriented question: If I have a function f in my base class, say that takes an integer, and I write an overload of that function in a derived class that takes something different, can I still call the original function that was inherited from the base class? The answer might surprise you.”

Mi¢ro$oft : “In standard C++, a function in a base class will be hidden by a function with the same name in a derived class, even if the derived class function does not have the same number or type of parameters. This is referred to as hide-by-name semantics.”

Signatures:

Dummies.com : “The return type is not part of the extended name (also known as the function signature) of the function.”

The rules for function name and signature resolution are captured by Koenig Lookup (a.k.a.: König Lookup, ADL, Argument Dependent [Name] Lookup).

[Aside: overloading by return type is possible.]

Advertisements

One Response to “C++: Hide-by-name Semantics and Signatures”

  1. Adrian Says:

    Thanks Rob! This is a great post.

    Also found this entry on name hiding in C++ to be helpful:

    http://www.programmerinterview.com/index.php/c-cplusplus/c-name-hiding/

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: