【问题标题】:parameterized constructor for inherited class templates继承类模板的参数化构造函数
【发布时间】:2019-12-14 13:24:36
【问题描述】:

我有多个继承类,但报错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);
}

【问题讨论】:

  • C1没有默认构造函数,只有一个带参数的构造函数。 C2 继承自 C1,但调用了 C2 的默认构造函数,该构造函数不存在。出于同样的原因,从 C2 继承的 C3 也存在同样的问题。编译器的错误信息非常清楚,并且确切地说明了这一点。这 ???是通过调用其构造函数来构造超类的示例。但这本身并不能解决这个问题,C2 调用 C1 的构造函数也需要同样的事情。

标签: c++ class templates c++17


【解决方案1】:

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

有两个修复:

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

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

    C2(F g) : C1 &lt;F&gt; (g), f2(g) {}

  • 同样C3s 构造函数,像这样:

    C3(F g) : C2 &lt;F&gt; (g), f3(g) {}

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

【讨论】:

    【解决方案2】:

    当您构造一个属于另一个类的子类时,将调用父类的默认构造函数(除非像在标记为??? 的行中那样显式调用另一个构造函数)。但是看到您为每个类提供了一个构造函数,编译器并没有生成一个隐式的默认构造函数。所以当你创建了一个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);
    }
    

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

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

    【讨论】:

    • 我在这里有点困惑。在实例化子类对象时,比如说o2,编译器是只调用父类的默认构造函数还是any父类的构造函数?
    • 当您使用C2(F g) : f2(g) { } 语法时,您没有显式调用C1 的构造函数,编译器将尝试隐式(在幕后)调用C1默认构造函数。但是,如果您的 C2 构造函数使用 C2(F g) : C1&lt;F&gt;(g), f2(g) { } 语法,在其中显式调用 some C1 构造函数,编译器将不会尝试隐式执行任何操作,而您会得到您所写的内容。
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 2016-03-04
      • 2019-12-14
      • 2013-05-07
      • 1970-01-01
      • 2016-02-17
      • 1970-01-01
      • 2021-07-13
      • 1970-01-01
      • 2013-03-25
      相关资源
      最近更新 更多