在构造函数中,候选者期望得到1个参数,0提供[duplicate]

时间:2021-06-24 18:48:55

This question already has an answer here:

这个问题已经有了答案:

This is the code:

这是代码:

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

And these are the errors:

这些是错误:

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

I don't understand the following:

我不明白以下几点:

  1. Why does the constructor for twoCats try to call the default constructor for cat? Surely it does not need to construct an instance of cat as when twoCats is initialised it will be passed an already initialised instance of cat which will have been passed the int height argument?
  2. 为什么twoCats的构造函数试图调用cat的默认构造函数?当然,当twoCats初始化时,它不需要构建一个cat实例,它将通过一个已经初始化的cat实例,该实例将通过int height参数传递?
  3. Why is the same block of error messages shown twice? I called g++ main.cpp on Ubuntu 12.04.
  4. 为什么同一块错误消息显示两次?我叫g++主要。cpp在Ubuntu 12.04。

4 个解决方案

#1


4  

You need a default constructor or initialize cat objects in twoCats constructor initilization list explicitly to avoid default construction.

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

Why does the constructor for twoCats try to call the default constructor for cat? Surely it does not need to construct an instance of cat as when twoCats is initialised it will be passed an already initialised instance of cat which will have been passed the int height argument?

为什么twoCats的构造函数试图调用cat的默认构造函数?当然,当twoCats初始化时,它不需要构建一个cat实例,它将通过一个已经初始化的cat实例,该实例将通过int height参数传递?

It needs to construct default values for cat objects

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

private:
    cat firstCat;
    cat secondCat;

in class twoCats because you didn't initialize them. In your constructor

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

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

this is assignment to already created objects.

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

The rule is as follows: if you don't initialize instances explicitly in ctor initialization list then

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

  1. Default ctor is called
  2. 默认的男星被称为
  3. You eventually assign to already default constructed objects in ctor body.
  4. 您最终将分配给ctor主体中已经默认构造的对象。

Thus you face penalty of having additional calls if you don't initialize in initialization list.

因此,如果在初始化列表中没有初始化,您将面临额外调用的惩罚。

C++ Standard n3337 § 12.6.2/10 Initializing bases and members

c++标准n3337§12.6.2/10初始化基地和成员

In a non-delegating constructor, initialization proceeds in the following order:

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

— First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.

——第一,只有最派生类的构造函数(1.8),虚拟基类初始化的顺序出现在有向无环图的深度优先遍历从左到右的基类,“从左到右”在哪里出现的顺序base-specifier-list基类的派生类。

— Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).

-然后,直接基类按声明顺序初始化,因为它们出现在基指定器列表中(而不考虑内存初始化器的顺序)。

Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).

-然后,非静态数据成员按照类定义中声明的顺序进行初始化(同样,不考虑内存初始化器的顺序)。

Finally, the compound-statement of the constructor body is executed.

最后,执行构造器主体的复合语句。

[ Note: The declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization. — end note ]

[注:声明令是为了确保基元和成员子对象在初始化的反向顺序中被销毁。——结束注意)

Here is a code demo.

这是一个代码演示。

#2


2  

I would initialize the class twoCats like this:

我这样初始化类两个ocats:

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

};

};

The important part here is the colon after the constructor :. It starts the member initialization list, which is the place where, if possible, all your class data members should be initialized.

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

Initialization of data members is quite a complex issue in C++, I suggest you google it.

在c++中,数据成员的初始化是一个非常复杂的问题,我建议您使用谷歌。

In particular, since you have two members of class type, the compiler, no matter what, tries to initialize them in your constructor. It does so for every cat, which probably is the reason you get the error message block twice. In its default, the compiler tries to initialize your cat data members using a default constructor, i.e. one without arguments. Unfortunately, cat does not have a default constructor, since you declared one with one argument. In other words, each cat has to be initialized with one argument (or copied, or moved in C++11).

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

I do not recommend declaring an additional constructor to cat without arguments: It seems that there is no "default hight" of a cat, and the -1 suggested by another answer is very strange: It doesn't seem to construct a valid object, and you'd have to check for this default value before using any of cat's member functions.

我不建议额外声明构造函数没有参数:猫似乎没有“默认高”的一只猫,和1建议由另一个答案是很奇怪的:它似乎并没有建立一个有效的对象,你必须检查这个默认值之前使用任何猫的成员函数。

EDIT: This is from a format point of view. As for the semantics of your program, it might be wrong to copy the cats. Maybe you do need a reference (or a pointer) to the objects you initialized your twoCats with, maybe not.

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

#3


1  

Both cat instances have to be initialized, at the point when they start existing.

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

To avoid this you can defer each instance creation to when you need it.

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

A simple and safe way to do that is to use a std::vector to hold the instances.

一种简单而安全的方法是使用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;}

Alternatively, you might use boost::optional.

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

Or allocate the instances dynamically (use a smart pointer such as unique_ptr to manage lifetime then).

或者动态地分配实例(使用智能指针,例如unique_ptr来管理生命周期)。

Or, let cats be default-constructible.

或者,让猫是默认构造的。


As noted by "thang" in a comment, the original design does not guarantee that a twoCats has two cats. It can have just one cat, or three or more cats. So it would be a good idea to change the design.

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

For example, have a constructor that takes two cat arguments, or cat heights.

例如,有一个构造函数接受两个cat参数,或者cat height。

Or for another example, changing the name of twoCats.

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

#4


0  

As name of your class (twoCats) states it represents two cats always. These kittens can be alive, dead or even not yet born. But it shall be two of them.

类的名称(twoCats)表示它总是代表两只猫。这些小猫可能是活的、死的,甚至还没有出生。但它将是其中的两个。

Your design is wrong in the sense that either:

你的设计在以下两个方面都是错误的:

  • cat should be able to represent non-born cat (so it should have public default constructor setting the object into non-born state initially) or
  • cat应该能够表示非出生的cat(因此它应该具有公共默认构造函数,最初将对象设置为非出生状态)或
  • your twoCats constructor shall accept exactly two cats at the very beginning.
  • 你的两个ats的构造者应该在一开始就接受两个cat。

#1


4  

You need a default constructor or initialize cat objects in twoCats constructor initilization list explicitly to avoid default construction.

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

Why does the constructor for twoCats try to call the default constructor for cat? Surely it does not need to construct an instance of cat as when twoCats is initialised it will be passed an already initialised instance of cat which will have been passed the int height argument?

为什么twoCats的构造函数试图调用cat的默认构造函数?当然,当twoCats初始化时,它不需要构建一个cat实例,它将通过一个已经初始化的cat实例,该实例将通过int height参数传递?

It needs to construct default values for cat objects

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

private:
    cat firstCat;
    cat secondCat;

in class twoCats because you didn't initialize them. In your constructor

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

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

this is assignment to already created objects.

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

The rule is as follows: if you don't initialize instances explicitly in ctor initialization list then

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

  1. Default ctor is called
  2. 默认的男星被称为
  3. You eventually assign to already default constructed objects in ctor body.
  4. 您最终将分配给ctor主体中已经默认构造的对象。

Thus you face penalty of having additional calls if you don't initialize in initialization list.

因此,如果在初始化列表中没有初始化,您将面临额外调用的惩罚。

C++ Standard n3337 § 12.6.2/10 Initializing bases and members

c++标准n3337§12.6.2/10初始化基地和成员

In a non-delegating constructor, initialization proceeds in the following order:

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

— First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.

——第一,只有最派生类的构造函数(1.8),虚拟基类初始化的顺序出现在有向无环图的深度优先遍历从左到右的基类,“从左到右”在哪里出现的顺序base-specifier-list基类的派生类。

— Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).

-然后,直接基类按声明顺序初始化,因为它们出现在基指定器列表中(而不考虑内存初始化器的顺序)。

Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).

-然后,非静态数据成员按照类定义中声明的顺序进行初始化(同样,不考虑内存初始化器的顺序)。

Finally, the compound-statement of the constructor body is executed.

最后,执行构造器主体的复合语句。

[ Note: The declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization. — end note ]

[注:声明令是为了确保基元和成员子对象在初始化的反向顺序中被销毁。——结束注意)

Here is a code demo.

这是一个代码演示。

#2


2  

I would initialize the class twoCats like this:

我这样初始化类两个ocats:

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

};

};

The important part here is the colon after the constructor :. It starts the member initialization list, which is the place where, if possible, all your class data members should be initialized.

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

Initialization of data members is quite a complex issue in C++, I suggest you google it.

在c++中,数据成员的初始化是一个非常复杂的问题,我建议您使用谷歌。

In particular, since you have two members of class type, the compiler, no matter what, tries to initialize them in your constructor. It does so for every cat, which probably is the reason you get the error message block twice. In its default, the compiler tries to initialize your cat data members using a default constructor, i.e. one without arguments. Unfortunately, cat does not have a default constructor, since you declared one with one argument. In other words, each cat has to be initialized with one argument (or copied, or moved in C++11).

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

I do not recommend declaring an additional constructor to cat without arguments: It seems that there is no "default hight" of a cat, and the -1 suggested by another answer is very strange: It doesn't seem to construct a valid object, and you'd have to check for this default value before using any of cat's member functions.

我不建议额外声明构造函数没有参数:猫似乎没有“默认高”的一只猫,和1建议由另一个答案是很奇怪的:它似乎并没有建立一个有效的对象,你必须检查这个默认值之前使用任何猫的成员函数。

EDIT: This is from a format point of view. As for the semantics of your program, it might be wrong to copy the cats. Maybe you do need a reference (or a pointer) to the objects you initialized your twoCats with, maybe not.

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

#3


1  

Both cat instances have to be initialized, at the point when they start existing.

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

To avoid this you can defer each instance creation to when you need it.

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

A simple and safe way to do that is to use a std::vector to hold the instances.

一种简单而安全的方法是使用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;}

Alternatively, you might use boost::optional.

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

Or allocate the instances dynamically (use a smart pointer such as unique_ptr to manage lifetime then).

或者动态地分配实例(使用智能指针,例如unique_ptr来管理生命周期)。

Or, let cats be default-constructible.

或者,让猫是默认构造的。


As noted by "thang" in a comment, the original design does not guarantee that a twoCats has two cats. It can have just one cat, or three or more cats. So it would be a good idea to change the design.

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

For example, have a constructor that takes two cat arguments, or cat heights.

例如,有一个构造函数接受两个cat参数,或者cat height。

Or for another example, changing the name of twoCats.

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

#4


0  

As name of your class (twoCats) states it represents two cats always. These kittens can be alive, dead or even not yet born. But it shall be two of them.

类的名称(twoCats)表示它总是代表两只猫。这些小猫可能是活的、死的,甚至还没有出生。但它将是其中的两个。

Your design is wrong in the sense that either:

你的设计在以下两个方面都是错误的:

  • cat should be able to represent non-born cat (so it should have public default constructor setting the object into non-born state initially) or
  • cat应该能够表示非出生的cat(因此它应该具有公共默认构造函数,最初将对象设置为非出生状态)或
  • your twoCats constructor shall accept exactly two cats at the very beginning.
  • 你的两个ats的构造者应该在一开始就接受两个cat。