C++ 构造函数 -- 通过引用传递仅适用于 const。为什么?

C++ Constructor -- pass by reference only works with const. Why?

提问人: 提问时间:11/9/2015 最后编辑:p.i.g. 更新时间:11/10/2015 访问量:1896

问:

所以今天早些时候,我正在赶上旧的C++,当我编译我的代码时,它不起作用。像一些程序员一样,我开始四处寻找,最终发现添加键盘可以解决这个问题。但是,我不太喜欢黑客攻击,并想知道为什么代码在添加 .constconst

这是我在将 添加到构造函数之前的代码:const

#include <iostream>
#include <string>

using namespace std;

class Names {
private:
    string _name;
    string _surname;

public:
    Names(string &name, string &surname) : _name(name), _surname(surname) {}

    string getName() const {return _name;}
    string getSurname() const {return _surname;}
};

int main(){
    Names names("Mike", "Man");

    cout << names.getName() << endl;
    cout << names.getSurname() << endl;
}

我收到这些错误:

names.cc:19:27: error: no matching function for call to ‘Names::Names(const char [5], const char [4])’
  Names names("Mike", "Man");
                           ^
names.cc:19:27: note: candidates are:
names.cc:11:2: note: Names::Names(std::string&, std::string&)
  Names(string &name, string &surname) : _name(name), _surname(surname) {}
  ^
names.cc:11:2: note:   no known conversion for argument 1 from ‘const char [5]’ to ‘std::string& {aka std::basic_string<char>&}’
names.cc:5:7: note: Names::Names(const Names&)
 class Names {
       ^
names.cc:5:7: note:   candidate expects 1 argument, 2 provided
<builtin>: recipe for target 'names' failed
make: *** [names] Error 1

但是,在构造函数中添加关键字后 - 它似乎正在工作。constNames(string const &name, string const &surname) : _name(name), _surname(surname) {}

这是我的工作代码:

#include <iostream>
#include <string>
using namespace std;

class Names {
private:
    string _name;
    string _surname;

public:
    Names(string const &name, string const &surname) : _name(name), _surname(surname) {}

    string getName() const {return _name;}
    string getSurname() const {return _surname;}

};

int main(){
    Names names("Mike", "Man");
    cout << names.getName() << endl;
    cout << names.getSurname() << endl;
}

现在,几个问题:

  1. 为什么代码在没有 for pass by 的情况下无法正常工作 参考?在您的 构造函数,如果是这样,这是否意味着我们必须使用关键字?constconst
  2. 因此,如果我在构造函数中按值传递,请说:这是否意味着 and 是 null 还是它们 传递的值。我知道在传递值中,变量的副本 正在制作中,并且正在对副本进行更改。但是什么时候 副本被删除或超出范围?这有点令人困惑。Names(string name, string surname) : _name(name), _surname(surname) {}_name_surname

谢谢

C++ C++11 参数传递 引用传递值

评论

0赞 Lightness Races in Orbit 11/9/2015
为什么对象会为“null”?ctor-initialiser 的全部目的是初始化成员。当封装对象这样做时,这些成员显然超出了范围!std::string
1赞 Lightness Races in Orbit 11/9/2015
要找到复制品是非常困难的,可能是因为它们都被否决了,被遗忘了。我知道我以前经常看到这个问题。
0赞 11/9/2015
在构造函数中通过引用传递是一种好做法吗?如果是这样,为什么?
1赞 Lightness Races in Orbit 11/9/2015
这是一个完全不同的问题。

答:

14赞 Cory Kramer 11/9/2015 #1

字符串文字必须转换为 ,这将是临时的,并且不能通过非常量引用传递临时文本。std::string

评论

0赞 11/9/2015
感谢您的回复。我仍然对这一切感到困惑。你能给我举个例子吗?
3赞 Lightness Races in Orbit 11/9/2015
@CodeMan:你的代码就是例子。你没有意识到的问题不是一个对象吗?和/或隐式转换导致暂时的?和/或临时性可能不受 ref-to-non- 的约束?这是三个独立的考虑因素,之前都在 SO 上回答过。虽然我同意这个答案需要充实。"a string literal like this"std::stringconst
0赞 decltype_auto 11/9/2015
@LightnessRacesinOrbit我认为在在线编译器商店中有一个带有生命周期检测的类通常很有用,并尝试根据该检测类“充实”临时部分“出来”。
0赞 Mustafa 11/9/2015 #2

1- 对构造函数的调用中的“Mike”和“Man”是临时的,非常量引用不能绑定到临时引用。 按值传递内置类型更有效,所有其他对象按常量引用传递效率更高。

2- 如果您按值传递并将具有传递的值。传递的参数副本是函数的本地副本,因此当构造函数超出范围时,它们将被销毁。_name_surname

2赞 decltype_auto 11/9/2015 #3

很难在@CoryKramer的解释中添加一些东西

字符串文本必须转换为 std::string,这将是 一个临时的,你不能通过非常量引用传递一个临时的。

这不仅仅是重新表述它。

无论如何,这里有一些你(@CodeMan)可以使用的检测代码

#include <iostream>

std::ostream& logger = std::clog;

struct A {
    A() = delete;
    A(int ii) : i(ii) {logger << "A(int) ctor\n";}
    A(const A& a) : i(a.i) {logger << "A copy ctor\n";}
    A& operator= (const A& a) { i = a.i; logger << "A copy assigment\n"; return *this;};
    // nothing to steal here
    A(A&& a) : i(a.i) {logger << "A move ctor\n";}
    A& operator= (A&& a) {i = a.i; logger << "A move assigment\n"; return *this;};
    ~A() {logger << "A dtor\n";}

    int i;
};

void foobar(const A& a) {
    logger << "foobaring const A&\n";
}

void foobar(A& a) {
    logger << "foobaring A&\n";
}


int main(){
  int i(42);  
  A a(i);
  logger << "ctored a\n===================\n";  
  foobar(a);
  logger << "foobared a\n-------------------\n";  
  foobar(i);
  logger << "foobared " << i << "\n===================" << std::endl;
}

住在 Coliru's。

从输出中可以看出

[...]
===================
foobaring A&
foobared a
-------------------
A(int) ctor
foobaring const A&
A dtor
foobared 42
===================
[...]

在第二次调用中,隐式地从该 int 参数中隐式地传递了一个临时实例,并且该临时实例被传递到另一个实例中,即 的 const 版本,因此作为 .foobarAAfoobarconst A &

你也可以,在第二个回来之后,那个临时的被扣留了。foobarA