继承类模板的参数化构造函数

parameterized constructor for inherited class templates

本文关键字:参数 构造函数 继承      更新时间:2023-10-16

我有多个继承的类,C2<int (__cdecl *)(int)>': no appropriate default constructor available错误,但我为C1,C2定义了参数化的构造函数。

一个相关的问题是我在某些代码中看到标记为???的注释行。这是什么意思 - 它正在初始化C3 C2的默认构造函数?

#include <iostream>
int y(int) 
{ int a=1; return a } 
template<typename F>
class C1
{
public:
    F f1;
    C1(F g) : f1(g) {}  
};
template<typename F>
class C2 : public C1<F>
{
public:
    F f2;
    C2(F g) : f2(g) {}  
};
template<typename F>
class C3 : public C2<F>
{
public:
    F f3;
    C3(F g) : f3(g) {}
    //C3 (F g) : C2<F>(g) {}        ???
};

int main()
{
    C1 o1(y);
    C2 o2(y);
    C3 o3(y);
}

当你构造一个类是另一个类的子类时,将调用父类的默认构造函数(除非显式调用另一个构造函数,如标记为 ??? 的行(。但是,当您为每个类提供了一个构造函数时,编译器没有生成隐式默认构造函数。所以当你创建一个C2的实例,并且编译器试图调用C1缺失的默认构造函数时,它找不到它。

如果您确实提供了默认构造函数,则此方法有效:

#include <iostream>
int y(int) {
    int a=1;
    return a;
} 
template<typename F>
class C1 {
public:
    F f1{};
    C1() = default;
    C1(F g)
        : f1(g)
    { }  
};
template<typename F>
class C2 : public C1<F>
{
public:
    F f2{};
    C2() = default;
    C2(F g) 
        : f2(g)
    { }  
};
template<typename F>
class C3 : public C2<F>
{
public:
    F f3{};
    C3() = default;
    C3(F g) 
        : f3(g) 
    { }
    //C3 (F g) : C2<F>(g) {}        ???
};

int main()
{
    C1 o1(y);
    C2 o2(y);
    C3 o3(y);
}

标记为 ??? 的行调用特定的父构造函数,而不是依赖于对父类的默认构造函数的隐式调用。

因此,您可以提供如上所述的默认构造函数,也可以采用???行语法来调用特定的构造函数 - 这取决于您的类设计和意图。

正如 Sam 所说,C2 的构造函数正在尝试调用不存在的 C1 的默认构造函数。 同样,C3尝试调用C2的默认构造函数。

有两个修复:

  • 定义 C1C2 的默认构造函数,或者:

  • 修改 C2 s 构造函数以调用确实存在的构造函数,如下所示:

    C2(F g) : C1 <F> (g), f2(g) {}

  • 类似地C3 s 构造函数,如下所示:

    C3(F g) : C2 <F> (g), f3(g) {}

我认为,这本身就回答了你的第二个问题。

C2<F>(g) 通过调用基类的构造函数来初始化基类。如果您自己不调用构造函数,则编译器将尝试调用基类(C2<F>::C2()(的默认构造函数。您的类都没有默认构造函数,这是错误的根源。但实际上你应该做的是自己调用基类构造函数。

C2(F g) : C1<F>(g), f2(g) {}
C3(F g) : C2<F>(g), f3(g) {}