【问题标题】:In constructor, candidate expects 1 argument, 0 provided [duplicate]在构造函数中,候选人需要 1 个参数,提供 0 [重复]
【发布时间】:2014-11-22 11:51:33
【问题描述】:

这是代码:

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

【问题讨论】:

  • 首先,你没有在你的构造函数中初始化任何东西。您分配给已经初始化的对象。其次,您只尝试初始化firstCatsecondCat 还能用什么?
  • 这已经被回答过无数次了。
  • @juanchopanza 至少你必须承认 OP 在第一枪就得到了正确的问题格式;) ...
  • @thang 这将是一项艰巨的工作,人类审稿人甚至很难在 SO 上找到合适的骗子。
  • 我感觉 OP 可能在笑着想“一群书呆子在分析我的家庭作业”

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


【解决方案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 有两只猫。它可以只有一只猫,也可以是三只或更多猫。所以最好改变设计

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

或者再举个例子,改变twoCats的名字。

【讨论】:

  • 我认为这很好,只是你可能会不小心多次添加第二只猫。在这种情况下,twoCats 就不是两只猫,这是以后产生 bug 的秘诀。
  • @thang:是的。我保留了设计。如果一个人开始改变设计,它就会变成......不同
  • 好吧,我认为如果存在必须是 twoCats(2 只猫)的约束,那么实现要么不应该使用向量(例如,2 个显式智能指针),要么使用向量并检查大小.关于这一点,addSecondCat 可能应该是 setSecondCat。类名和(部分)声明要求 1-2 关联。
  • @thang: 是的,或者改个名字。但由于无法访问猫甚至数它们,因此任何不正确的用法都可能会被忽视。 ;-)
  • 是的,它是“只写内存”...
【解决方案2】:

您需要一个默认构造函数或在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)的构造函数, 虚拟基类按照它们出现在 有向无环图的深度优先从左到右遍历 基类,其中“从左到右”是出现的顺序 派生类 base-specifier-list 中的基类。

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

然后,非静态数据成员按照它们的顺序初始化 在类定义中声明(同样不管 内存初始化器)。

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

[注:声明顺序的任务是确保基础和 成员子对象以相反的顺序被销毁 初始化。 ——尾注]

Here is a code demo.

【讨论】:

  • 这一切都很好,但我认为它不能回答问题,并且会引入性能问题
  • @Cheersandhth.-Alf 是的,谢谢,已更改
  • 非常感谢您的澄清,完美的答案,这正是我想要的!
【解决方案3】:

正如你的班级名称 (twoCats) 所说,它代表两只猫总是。这些小猫可能是活着的、死去的,甚至还没有出生。但应该是两个。

你的设计是错误的:

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

【讨论】:

  • 嗯,设计没有错。这取决于要求:p 可能是打算拥有一组最多 2 只猫和至少 1 只猫。
  • 我提出的 MWE 没有经过深思熟虑,是的,对于这个例子,我真的应该确保构造函数只能接受两只猫,所以应该总是有两个猫对象 :)跨度>
【解决方案4】:

我会像这样初始化类twoCats

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

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

数据成员的初始化在C++中是一个比较复杂的问题,建议你google一下。

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

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

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

【讨论】:

  • 谢谢,这很有帮助,我认为对于我的实际问题(这个猫程序只是一个 MWE)我会使用指针来解决问题
猜你喜欢
  • 2012-02-11
  • 1970-01-01
  • 2018-04-20
  • 1970-01-01
  • 2020-04-11
  • 1970-01-01
  • 2016-01-10
  • 2019-08-28
  • 2022-09-24
相关资源
最近更新 更多