简体   繁体   中英

Accessing template base class's constructor from derived class

Please consider the following scenario:
1) A parameterized base class A<T>
2) A parameterized derived class B<T> deriving from A<T>.

When the derived class' ctor tries to reference the base class, a compilation error occurs:

/** Examines how to invoke the Base class ctor
    from the Derived class,
    when both classes are templates.
*/

#include <iostream>

using namespace std;


template<typename T>
class A                     /// base class
{
public:
    A(int i)
    {
    }
};


template<typename T>
class B : public A<T>         /// derived class
{
public:
    B(int i) :
        A {i}
    {
    }
};


int main()
{
    A<int> a {5};
    B<int> b {10};
}


Errors:

\main.cpp||In constructor 'B<T>::B(int)':|
\main.cpp|26|error: class 'B<T>' does not have any field named 'A'|

\main.cpp||In instantiation of 'B<T>::B(int) [with T = int]':|
\main.cpp|35|required from here|
\main.cpp|26|error: no matching function for call to 'A<int>::A()'|

\main.cpp|26|note: candidates are:|
\main.cpp|15|note: A<T>::A(int) [with T = int]|
\main.cpp|15|note:   candidate expects 1 argument, 0 provided|
\main.cpp|12|note: constexpr A<int>::A(const A<int>&)|
\main.cpp|12|note:   candidate expects 1 argument, 0 provided|
\main.cpp|12|note: constexpr A<int>::A(A<int>&&)|
\main.cpp|12|note:   candidate expects 1 argument, 0 provided|
||=== Build failed: 2 error(s), 2 warning(s) (0 minute(s), 0 second(s)) ===|


The compiler interprets the B class's ctor as initializing a field A in the B class, rather than as invoking the A class' ctor.

How can this be fixed?

The name of the base class, when used in B<T> 's constructor, is a dependent name , because what it refers to depends on the template argument T . See https://en.cppreference.com/w/cpp/language/dependent_name .

The name lookup rules are different. Names are not available in the current scope (ie the constructor of B<T> ), if they depend on template arguments of the current scope ( T ).

In that case the entire full name needs to be specified in B :

template<typename T>
class B : public A<T>         /// derived class
{
public:
    B(int i) :
        A<T> {i}
    {
    }
};

The same is true when accessing members of the base class in the derived class, for example it is necessary to do:

template<typename T>
class B : public A<T>
{
public:
    void f()
    {
        A<T>::g();  // defined in A
    }
};

In that case this->g() does also work, but it can have a different meaning.

It may be useful to define a typedef of the base class as a member of B<T> , for example:

class B : public A<T>         /// derived class
{
    using base = A<T>;
public:
    B(int i) :
        base {i}
    {
    }
};

Then the base class's template arguments need to be repeated only one time in the code.

The injected class name will only work within that class not the derived class so change the code to following:

#include <iostream>

using namespace std;


template<typename T>
class A                     /// base class
{
public:
    A(int i)
    {
    }
};


template<typename T>
class B : public A<T>         /// derived class
{
public:
    B(int i) :
        A<T> {i} // added <T>
    {
    }
};


int main()
{
    A<int> a {5};
    B<int> b {10};
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM