In C++, a function in a derived class with the same name as one (or a set of overloads) in a base class, hides the function (or the overloads) from the base class. Here is an example:

struct base { void foo() {std::cout << "base::foo" << endl;} void foo(int a) {std::cout << "base::foo(" << a << ")" << endl;} void foo(int a, double b) {std::cout << "base::foo(" << a << "," << b << ")" << endl;} }; struct derived : base { void foo(double a) {std::cout << "derived::foo(" << a << ")" << endl;} }; int main() { derived d; d.foo(); // error: derived::foo does not take 0 arguments d.foo(42); d.foo(42, 3.14); // error: derived::foo does not take 2 arguments return 0; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 struct base { void foo ( ) { std :: cout << "base::foo" << endl ; } void foo ( int a ) { std :: cout << "base::foo(" << a << ")" << endl ; } void foo ( int a , double b ) { std :: cout << "base::foo(" << a << "," << b << ")" << endl ; } } ; struct derived : base { void foo ( double a ) { std :: cout << "derived::foo(" << a << ")" << endl ; } } ; int main ( ) { derived d ; d . foo ( ) ; // error: derived::foo does not take 0 arguments d . foo ( 42 ) ; d . foo ( 42 , 3.14 ) ; // error: derived::foo does not take 2 arguments return 0 ; }

As the comments show, calls to foo() and foo(42, 3.14) trigger compiler errors. The call to foo(42) is all right because there is an implicit conversion from int to double .

It is possible to “un-hide” the functions from the base class with a using directive.

struct derived : base { void foo(double a) {std::cout << "derived::foo(" << a << ")" << endl;} using base::foo; }; 1 2 3 4 5 struct derived : base { void foo ( double a ) { std :: cout << "derived::foo(" << a << ")" << endl ; } using base :: foo ; } ;

The code in main will now compile and the program will output:

base::foo base::foo(42) base::foo(42,3.14) 1 2 3 base :: foo base :: foo ( 42 ) base :: foo ( 42 , 3.14 )

A limitation of this feature was that it didn’t work with constructors. In other words the following is failing to compile.

struct base { base() {std::cout << "base()" << endl;} base(int a) {std::cout << "base(" << a << ")" << endl;} base(int a, double b) {std::cout << "base(" << a << "," << b << ")" << endl;} }; struct derived : base { using base::base; }; int main() { derived d1; derived d2(42); derived d3(42, 3.14); return 0; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 struct base { base ( ) { std :: cout << "base()" << endl ; } base ( int a ) { std :: cout << "base(" << a << ")" << endl ; } base ( int a , double b ) { std :: cout << "base(" << a << "," << b << ")" << endl ; } } ; struct derived : base { using base :: base ; } ; int main ( ) { derived d1 ; derived d2 ( 42 ) ; derived d3 ( 42 , 3.14 ) ; return 0 ; }

This can be achieved by writing a matching constructor in the derived for every constructor in base.

struct derived : base { derived():base() {} derived(int a):base(a) {} derived(int a, double b):base(a, b) {} }; 1 2 3 4 5 6 struct derived : base { derived ( ) : base ( ) { } derived ( int a ) : base ( a ) { } derived ( int a , double b ) : base ( a , b ) { } } ;

However, when you have hierarchies with many derives and you have to provide one or more constructors like this just to call the right constructor of base it becomes annoying.

A solution to the problem is provided by C++ 11. The using directive now works also for constructors. The derived class in the last example is semantically equivalent to

struct derived : base { using base::base; }; 1 2 3 4 struct derived : base { using base :: base ; } ;

This code will produce the following output:

int main() { derived d1; derived d2(42); derived d3(42, 3.14); return 0; } 1 2 3 4 5 6 7 8 int main ( ) { derived d1 ; derived d2 ( 42 ) ; derived d3 ( 42 , 3.14 ) ; return 0 ; }

base() base(42) base(42,3.14) 1 2 3 base ( ) base ( 42 ) base ( 42 , 3.14 )

Keep in mind that the lifted constructors are simply calling the base constructors and do not perform any member initialization. Suppose you had some member like in the following example:

struct derived : base { using base::base; int value; }; 1 2 3 4 5 6 struct derived : base { using base :: base ; int value ; } ;

Regardless what constructor is used to create the object, value will remain uninitialized. To avoid that you have two options:

don’t use the using directive to lift the constructors from base and write the constructors for the derived class explicitly

initialize the member variables explicitly (using non-static data member initializers):

struct derived : base { using base::base; int value {0}; }; 1 2 3 4 5 6 struct derived : base { using base :: base ; int value { 0 } ; } ;

Availability. At the time of writing this post, inherited constructors are supported by g++ 4.8 and clang 3.3. Visual Studio does not support it and is not known in which version in the future it will. Non-static data member initializers are supported by Visual Studio 2013 RTM, g++ 4.7 and clang 3.0.

Share this: Twitter

LinkedIn

StumbleUpon

Facebook

Reddit

More

Google

Email



Print

