【问题标题】:C++: how to pass an object to another object constructor?C++:如何将一个对象传递给另一个对象构造函数?
【发布时间】:2015-08-01 14:45:30
【问题描述】:

我知道这个问题被问了很多,但我来自 Java,很长时间没有做过任何 C/C++。

你能提醒我如何在 C++ 中正确地将一个对象传递给另一个对象的构造函数吗?

例如,我需要将一个新的 Light 对象传递给 Button 构造函数:

// LED Light
class Light {
    int pin;

    public:
        Light(int p) {
            pin = p;
        }
};

// BUTTON
class Button {
    Light ledLight;

    public:
        Button(Light l) {
            ledLight = l;
        }

};

Light my_led(0);

Button my_button(my_led);

这就是我在类似 Java 的方式中的做法。 但是,这会产生以下错误:

::  In constructor ‘Button::Button(Light)’:
::  16:19: error: no matching function for call to ‘Light::Light()’
::  16:19: note: candidates are:
::  6:3: note: Light::Light(int)
::  6:3: note:   candidate expects 1 argument, 0 provided
::  2:7: note: Light::Light(const Light&)
::  2:7: note:   candidate expects 1 argument, 0 provided

对象是通过引用传递还是在我创建新按钮时尝试创建新对象?

或者我需要在Button的构造函数中将Light声明为指针吗?

非常感谢任何帮助!

【问题讨论】:

  • 现在写100次:“C is not C++ is not C!”
  • 另外值得注意的是,与 Java 不同,对my_button.ledLight 的更改不会更改my_led 的内容。您复制了对象。
  • @Olaf,我真的很抱歉,特别是惭愧,因为我自己经常要求人们用“Java/JavaScript”做同样的事情。感谢您的编辑。 @BillLynch,我如何将my_led 直接传递给my_button?这样按钮的更改会影响其内容。
  • @YemSalat 您可以将ledlight 设为参考
  • @awesomeyi,喜欢这样吗? Light& ledLight; 然后:Button(Light& l) { } 在构造函数声明中?

标签: c++ constructor pass-by-reference


【解决方案1】:

程序尝试使用默认构造函数初始化ledLight,然后将l 分配给ledLight。编译器给你一个错误,因为Light 没有默认构造函数。试试这个:

Button(Light l): ledLight(l) { }

【讨论】:

  • 谢谢!但是,如果我有更多参数,正确的语法是什么,例如:Button(int pin, long time, Light l)
  • @YemSalat 你可以试试Button(int pin, long time, Light l): b_pin(pin), b_time(time), ledLight(l) {}
  • 另外,请记住,当您以这种方式构造对象时,它们将在块结束时被销毁(函数、循环、if 子句等)。如果您希望 Light 对象的寿命更长,则必须使用 new Light(0) 并将其作为指向 Button 的指针(最好是共享指针)传递。
  • 但不只是将其重写为Button(Light& l): ledLight(l) { } 就可以了?我还需要更改将其传递给构造函数的方式吗?
  • @MaciejDziuban:这根本不是真的。 Light 将被复制以进行存储。您对动态分配的建议走错了方向。
【解决方案2】:

您缺少默认构造函数。尝试像这样修改你的类:

class Light {
    int pin;

    public:
        Light()=default;  //<-- put this in
        Light(int p) {
            pin = p;
        }
};

至于你为什么不自动生成默认构造函数,那是因为你已经声明了某种类型的构造函数,所以编译器不会生成默认构造函数(来自http://en.cppreference.com/w/cpp/language/default_constructor,请参阅隐式声明的部分/定义的构造函数)。


回应评论:

它不会尝试调用默认构造函数而不是那个 哪个传递参数?

当你的执行代码到达最后一行时:

Button my_button(my_led);

您正在实例化 ButtonLight 作为 Button 实例化过程的一部分。如果不指定默认的Light::Light() 构造函数,您将忽略有关如何实例化没有值的Light 对象的说明,您需要在将my_led 的值复制到my_button 之前执行此操作。您将获得您想要的结果,您目前只是向编译器遗漏了有关如何执行中间步骤的说明,即在不带任何参数的情况下实例化 Light


需要考虑的一些事情:

真正想做什么?只需查看您的指令代码:

Light my_led(0);

Button my_button(my_led);

在我看来,您似乎想说“存在名为 my_led 的灯”和“存在名为 my_button 的按钮并需要 my_led”。您希望该按钮引用已存在的特定 LED,还是仅引用具有相同值的 LED?

如果您认为您希望通过该按钮引用实际的 LED,那么您可能需要考虑执行以下操作:

class Button {
    const Light *ledLight;

    public:
        Button(const Light& l) : 
            ledLight{&l}
        {}
};

这样,您的Button 有一个指向您创建的Light 的指针,并且您在Button 代码中对Light 执行的任何操作都将在您已经实例化的Light 对象上执行,而不是您通过使用当前的 Button 构造函数复制构造 Light 创建的 Light 的一些单独副本。

如果您希望按钮实际修改灯光,请修改Button,如下所示:

class Button {
    // constant reference to changeable object
    Light *  const ledLight; 

    public:
        /**
         * You're providing a reference to a light that can be changed 
         * (i.e. button code can toggle lit status or something)
         */
        Button(Light & l) : 
            ledLight{&l}
        {}
};

您可以将上述内容视为从按钮到 LED 的不变导线。如果您认为您将重新分配从按钮点亮的 LED,您也可以从 Button 中的指针成员中取出 const 关键字。

【讨论】:

  • 它不会尝试调用默认构造函数而不是传递参数的构造函数吗?
  • 如果显式定义构造函数,则不会自动创建默认的构造函数
  • @YemSalat 当您执行Button my_button(my_led); 时,您已经在调用默认的Light::Light() 构造函数来在实例化Button 时首先实例化Light 成员。然后复制Button::Button(Light) 构造函数中提供的Light 的值。
  • @TJOlaes 非常感谢您的解释!您完全正确,我正在尝试做,每个按钮都需要控制实际的 LED。但是,当我为 Button 类运行代码时,出现以下错误:In constructor ‘Button::Button(const Light&amp;)’:error: cannot convert ‘const Light’ to ‘const Light*’ in assignment 这样我仍然将它传递给构造函数:Button my_button(my_led); 即它会自动知道这是对对象,不需要复制?
  • 我的错,我在建议的修订中留下了一些复制的文本。我相应地对其进行了修改。这个想法是您将光的只读引用传递给按钮。如果您希望按钮以某种方式修改灯光(例如将其状态更改为“点亮”之类的),您需要省略 const 关键字。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-15
  • 1970-01-01
  • 2019-03-09
  • 1970-01-01
  • 2017-06-03
相关资源
最近更新 更多