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

In constructor, candidate expects 1 argument, 0 provided

本文关键字:参数 构造函数 候选者 1个      更新时间:2023-10-16

这是代码:

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

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

为什么twoCats的构造函数试图调用默认cat的构造函数?当然,它不需要构造实例当初始化twoCats时,它将被传递一个将被传递int高度的cat的初始化实例论点

它需要为cat对象构造默认值

private:
    cat firstCat;
    cat secondCat;

在类twoCats中,因为您没有初始化它们。在您的构造函数中

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

这是对已创建对象的分配。

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

  1. 调用默认ctor
  2. 最终将指定给ctor主体中已默认构造的对象

因此,若并没有在初始化列表中进行初始化,那个么将面临额外调用的惩罚。

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

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

--首先并且仅对于最派生类(1.8)的构造函数,虚拟基类按照它们在的有向无环图的深度优先左到右遍历基类,其中"从左到右"是派生类基类说明符列表中的基类。

--然后,直接基类按声明顺序初始化为它们出现在基说明符列表中(无论mem初始化器)。

--然后,按非静态数据成员的顺序初始化在类定义中声明(无论mem初始化器)。

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

[注:申报令旨在确保成员子对象的销毁顺序与初始化。--尾注]

这是一个代码演示。

我会这样初始化类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的任何成员函数之前,都必须检查这个默认值。

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

两个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来管理生存期)。

或者,让猫默认为可构造的。


正如"thang"在评论中所指出的,最初的设计并不能保证twoCats有两只猫。它可以只有一只猫,也可以有三只或更多只猫。因此,更改设计是个好主意。

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

或者,例如,更改twoCats的名称。

作为类(twoCats)的名称,它表示两个猫始终。这些小猫可以是活的,也可以是死的,甚至还没有出生。但这将是他们中的两个。

你的设计是错误的,要么:

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