【问题标题】:Compiler can't see argument编译器看不到参数
【发布时间】:2017-11-10 13:30:02
【问题描述】:

我是 C++ 新手,想玩转类。

我的代码

在我的世界里有英雄和剑。英雄携带剑。这应该不会太难。

// Defining swords                                                                                                                                 
class Sword
{
  // The most important thing about a sword is its length.                                                                                         
  int lenght;
public:
  // only constructor and destructor                                                                                                               
  Sword(int swordlength){
    lenght = swordlength;
  };
  ~Sword(){};
};

// defining heros (as people with magic swords)                                                                                                    
class Hero
{
  Sword magic_sword;
public:
  // each hero gets a standard sword                                                                                                               
  Hero(){
    int meters = 2;
    magic_sword = Sword(meters);
  };
  ~Hero(){};
};

int main(){
  return 0;
}

编译器是怎么想的

当我编译这段代码 (g++ hero.cpp) 时出现错误:

 In constructor 'Hero::Hero()':
20:9: error: no matching function for call to 'Sword::Sword()'
20:9: note: candidates are:
8:3: note: Sword::Sword(int)
8:3: note:   candidate expects 1 argument, 0 provided
2:7: note: constexpr Sword::Sword(const Sword&)
2:7: note:   candidate expects 1 argument, 0 provided

我认为问题是什么

clang++编译代码也失败了,但是错误信息不是很明确,所以这里就不贴了。

似乎调用构造函数 Sword(meters) 失败了,因为我提供了 0 而不是 1 参数。但是我清楚地给了它一个论据(meters),所以我想我在这里误解了一些东西。

我的错误是什么,我能做些什么?

【问题讨论】:

  • Hero() : magic_sword(2) { /* 你的 ctor */ } .建造英雄时需要建造剑。当它进入 ctor 中的代码时,Hero 字段已经构建好了。

标签: c++ class constructor


【解决方案1】:

您的Hero 始终有一个Sword

这意味着,在类被实例化的那一刻,在Hero::Hero 构造函数开始运行之前,它已经必须有一个“默认”Sword。编译器抱怨它不知道如何制作这样的“默认”Sword

现在,您可以通过多种方式解决此问题:

使用初始化列表

在构造函数的定义中,您可以指定如何对象的成员应该初始化实际构造函数运行之前)。这不同于在构造函数的主体中为它们分配一个新值(在您的示例中发生)。为此,请在构造函数的签名后指定一个冒号 (:),然后是成员字段初始值设定项,如下所示:

Hero() : magic_sword(2)
{
  // do other stuff to set up your hero
}

这将导致magic_sword 立即使用Sword::Sword(int) 构造函数进行初始化,这意味着您不需要有默认的Sword::Sword() 构造函数。

阅读更多:Understanding Initialization Lists in C++

使用指针

您真的希望您的Sword 完全属于您的Hero 吗?你的Hero 可以放下一个Sword,然后另一个Hero 接起来吗?

在这种情况下,您可能不希望您的 Hero 拥有一个 Sword 作为成员 - 相反,您需要一个指向他当前所在的 Sword指针持有 - 例如,如果他没有持有剑,则可能是 nullptr

【讨论】:

  • 感谢您的解释。这行得通。我还不想使用指针——当你来自函数式语言时,它们很可怕。
  • @Kaligule 如果答案解决了您的问题,请考虑通过单击投票按钮旁边的复选标记来接受它。
  • 是的,指针可能很可怕。 C++ 是一个大池塘,你最终会到达那里。
【解决方案2】:

您的Sword 类没有没有参数的构造函数。在Hero()开头(在{开头之前),initializer list中未指定的成员默认构造。

试试这个:

Hero() : magic_sword(2) {
};

或者您可以向Sword 添加另一个不带参数的构造函数。

Sword(){
    lenght = -1;
};

【讨论】:

  • 您忘记了 () 和米之间的 :。
  • meters 不是Hero 的成员,这不应该编译
  • @AndreiAndrey 哎呀 :) (最近 C++ 做得不够)
  • @Treeston 已修复。
  • 现在meters 未定义。有关问题的更简洁说明,请参阅我的答案。
【解决方案3】:

(让我猜猜 - 你是从 Java 来的?)

编译器是正确的。 Sword 没有默认构造函数,有问题。

到代码中的这一点,

public:
  Hero(){
    // This point.

C++ 要求 magic_sword 已经构建。与 Java 不同,没有“null”值可用作默认值。到那时构造Sword 的唯一方法是使用Sword 没有的无参数构造函数。

当然,有一种方法可以使代码正常工作。语法如下:

public:
  Hero() : magic_sword(2) {

  }

这告诉编译器如何在Hero 的构造函数主体开始之前调用Sword 的构造函数。

请注意您的设计:您可能需要 magic_sword 作为某种指针(原始、唯一或引用计数)。与 Java 不同,所写的magic_sword 不是对Sword 实例的引用,而是一个实际实例,完全包含在Hero 实例中。

【讨论】:

  • 谢谢,这很有帮助。 (我在 5 年前开始使用 Java 进行编程,但从那以后我使用了更多的 Python)。
  • Python 也有同样的做法:实例属性是引用,而不是嵌入在所有者中的实际实例,对吧?
猜你喜欢
  • 1970-01-01
  • 2017-05-07
  • 2013-03-15
  • 2015-10-08
  • 1970-01-01
  • 2022-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多