在构造函数中,候选者需要1个参数,0提供

时间:2014-09-27 16:53:55

标签: c++ compiler-errors g++

这是代码:

class cat
{
    private:
        int height;
    public:
        cat (int inputHeight);
};

cat::cat (int inputHeight)
{
    height = inputHeight;
}

class twoCats
{
    private:
        cat firstCat;
        cat secondCat;
    public:
        twoCats (cat theFirstCat);
        void addSecondCat (cat theSecondCat);
};

twoCats::twoCats (cat theFirstCat)
{
    firstCat = theFirstCat;
}

void twoCats::addSecondCat (cat theSecondCat)
{
    secondCat = theSecondCat;
}

int main() {return 0;}

这些是错误:

main.cpp: In constructor ‘twoCats::twoCats(cat)’:
main.cpp:24:34: error: no matching function for call to ‘cat::cat()’
main.cpp:24:34: note: candidates are:
main.cpp:9:1: note: cat::cat(int)
main.cpp:9:1: note:   candidate expects 1 argument, 0 provided
main.cpp:1:7: note: cat::cat(const cat&)
main.cpp:1:7: note:   candidate expects 1 argument, 0 provided
main.cpp:24:34: error: no matching function for call to ‘cat::cat()’
main.cpp:24:34: note: candidates are:
main.cpp:9:1: note: cat::cat(int)
main.cpp:9:1: note:   candidate expects 1 argument, 0 provided
main.cpp:1:7: note: cat::cat(const cat&)
main.cpp:1:7: note:   candidate expects 1 argument, 0 provided

我不明白以下内容:

  1. 为什么twoCats的构造函数会尝试调用cat的默认构造函数?当然,它不需要构造cat的实例,因为初始化twoCats时它将传递已经初始化的cat实例,该实例将传递int height参数?
  2. 为什么同一块错误消息显示两次?我在Ubuntu 12.04上打电话给g++ main.cpp

4 个答案:

答案 0 :(得分:5)

您需要一个默认构造函数或明确初始化twoCats构造函数初始化列表中的cat对象,以避免默认构造。

  

为什么twoCats的构造函数会尝试调用默认值   猫的构造函数?当然它不需要构造一个实例   当catC初始化时,它将被传递   初始化的cat实例,它将传递给int高度   参数

需要为cat个对象构建默认值

private:
    cat firstCat;
    cat secondCat;
在课程twoCats

因为您没有初始化它们。在你的构造函数

cat::cat (int inputHeight)
{
    height = inputHeight;
    ^^^^^^^^^^^^^^^^^^^^
}   // this is assignment

这是对已创建对象的赋值。

规则如下:如果你没有在ctor初始化列表中显式初始化实例,那么

  1. 默认ctor被称为
  2. 您最终会在ctor body。
  3. 中分配已经默认的构造对象

    因此,如果未在初始化列表中初始化,则会面临额外调用的惩罚。

    C ++标准版n3337 § 12.6.2 / 10初始化基础和成员

      

    在非委托构造函数中,初始化继续进行   以下顺序:

         

    - 首先,仅适用于派生程度最高的类(1.8)的构造函数,   虚拟基类按照它们出现在的顺序进行初始化   深度优先从左到右遍历有向无环图   基类,其中“从左到右”是出现的顺序   派生类base-specifier-list中的基类。

         

    - 然后,直接基类按声明顺序初始化为   它们出现在base-specifier-list中(无论顺序如何   MEM-初始化)。

         

    - 然后,按照它们的顺序初始化非静态数据成员   在类定义中声明(再次无论顺序如何   MEM-初始化)。

         

    - 最后,执行构造函数体的复合语句

         

    [注:声明命令的目的是确保基础和   成员子对象以相反的顺序销毁   初始化。 - 结束说明]

    Here is a code demo.

答案 1 :(得分:2)

我会像这样初始化类twoCats

class twoCats
{
private:
    cat firstCat;
    cat secondCat;
public:
    twoCats (const cat& theFirstCat, const cat& theSecondCat)
        : firstCat (theFirstCat), secondCat (theSecondCat)
    {
    }

};

这里重要的部分是构造函数:之后的冒号。它启动成员初始化列表,如果可能的话,应该初始化所有类数据成员。

数据成员的初始化在C ++中是一个非常复杂的问题,我建议你谷歌吧。

特别是,由于您有两个类类型的成员,编译器无论如何都会尝试在构造函数中初始化它们。它对每只猫都这样做,这可能是你得到错误消息块两次的原因。在默认情况下,编译器尝试使用默认构造函数(即没有参数的构造函数)初始化cat数据成员。不幸的是,cat没有默认的构造函数,因为你用一个参数声明了一个。换句话说,每个cat必须用一个参数初始化(或复制,或在C ++ 11中移动)。

我不建议在没有参数的情况下向cat声明一个额外的构造函数:似乎没有猫的“默认高度”,而另一个答案建议的-1非常奇怪:它似乎没有构造一个有效的对象,你必须在使用任何cat的成员函数之前检查这个默认值。

编辑:这是从格式的角度来看。至于程序的语义,复制猫可能是错误的。也许你确实需要一个引用(或指针)你初始化你的两个猫的对象,可能不是。

答案 2 :(得分:1)

两个cat实例必须在它们开始存在时初始化。

为避免这种情况,您可以在需要时将每个实例创建推迟。

一种简单而安全的方法是使用std::vector来保存实例。

class cat
{
    private:
        int height;
    public:
        cat (int inputHeight);
};

cat::cat (int inputHeight)
{
    height = inputHeight;
}

#include <vector>
#include <utility>

class twoCats
{
    private:
        std::vector<cat> cats_;

    public:
        twoCats (cat theFirstCat)
        { cats_.push_back( std::move( theFirstCat ) ); }

        void addSecondCat (cat theSecondCat)
        { cats_.push_back( std::move( theSecondCat ) ); }
};

int main() {return 0;}

或者,您可以使用boost::optional

或动态分配实例(使用unique_ptr之类的智能指针来管理生命周期。)

或者,让猫可以默认构建。


a comment中的“thang”所述,原始设计并不能保证twoCats有两只猫。它可以只有一只猫,或三只或更多只猫。因此,更改设计是个好主意。

例如,有一个带有两个cat参数或cat高度的构造函数。

或者换个例子,更改twoCats的名称。

答案 3 :(得分:0)

作为你的班级名字(twoCats),它代表两只猫总是。这些小猫可以活着,死亡甚至还没有出生。但它应该是两个。

你的设计在某种意义上是错误的:

  • cat应该能够代表非出生的猫(所以它应该有 公共默认构造函数最初将对象设置为非生成状态)或
  • 你的twoCats构造函数一开始就应该接受两只猫。