从派生类访问模板基类的构造函数

时间:2018-07-04 11:13:09

标签: c++

请考虑以下情形:
1)参数化的基类A
2)从A 派生的参数化派生类B

当派生类的ctor尝试引用基类时,会发生编译错误:

/** 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};
}


错误:

\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)) ===|


编译器将B类的ctor解释为初始化B类中的字段A,而不是调用A类的ctor。

如何解决?

2 个答案:

答案 0 :(得分:4)

基类的名称在B<T>的构造函数中使用时,是一个依赖的名称,因为它所引用的内容取决于模板参数T。参见https://en.cppreference.com/w/cpp/language/dependent_name

名称查找规则不同。如果名称依赖于当前范围(B<T>)的模板参数,则它们在当前范围(即T的构造函数)中不可用。

在这种情况下,需要在B中指定完整的全名:

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

访问派生类中基类的成员时也是如此,例如,必须这样做:

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

在这种情况下,this->g()也可以工作,但是它可以具有不同的含义。

将基类的typedef定义为B<T>的成员可能会很有用,例如:

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

然后,基类的模板参数只需在代码中重复一次。

答案 1 :(得分:1)

注入的类名将仅在该类中起作用,而不能在派生类中起作用,因此将代码更改为以下内容:

#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};
}