2016-06-25 3 views
3

Допустим, у меня есть класс A:Const ссылка инициализации класса

class A { 
    int i; 
public: 
    A(){}; 
    A(int i){this->i=i;}; 
}; 

И простой тест функции:

void test(const A &a){...} 

Теперь, если я:

int main() 
{ 
    test(2); 
} 

It компилируется, и он будет вызывать конструктор A(int i). Но когда я изменяю аргумент как не const: void test(A &a) Я получаю ошибку компиляции.
В чем разница между этими случаями, почему первая разрешена, а вторая нет, и что на самом деле происходит при инициализации первого случая?

+0

см. Http://stackoverflow.com/questions/8293426/error-invalid-initialization-of-non-const-reference-of-type-int-from-an-rval – twin

+0

Думаю, вам стоит взглянуть на [это ] (http://stackoverflow.com/questions/3895647/why-const-for-implicit-conversion) тоже. – meJustAndrew

ответ

1

Разница между этими двумя случаями заключается в том, что компилятору C++ разрешено создавать временные объекты, которые должны передаваться функциям, принимающим ссылки const, но функции, принимающие ссылки не должны const должны быть снабжены реальными объектами.

Когда вы звоните test(2), что на самом деле это происходит:

A hidden(2); 
test(hidden); 

Компилятор создает hidden объект, инициализирует его 2, и передает результат test. Так как test гарантированно не изменяет A, это нормально.

Когда test не дает такой гарантии: представьте себе test, который устанавливает новое значение:

void test(A& a) { 
    a.i++; // let's pretend "i" is public 
} 

Если вы звоните test с реальным объектом, т.е. A a(3); test(a); вы можете собрать урожай результат обновления из a после test вернуть. С другой стороны, вызов test(2) не дает вам доступа к результату обновления. Это указывает на потенциальную ошибку в логике, поэтому компилятор рассматривает ее как ошибку.

0

Что на самом деле происходит при инициализации первого случая?

В 1-ом случае, временный A будет построен неявно A::A(int), а затем связывается с Lvalue ссылкой на Уст. Эффект test(2); такой же, как у test(A(2));.

Временное не может быть привязано к значению lvalue для не-const, поэтому 2-й случай не удался.

0

Это интересный случай. используя const, вы можете привязать ссылку к rvalue. Ниже приведен более простой пример.

int get_num() 
{ 
    return 2; 
} 

int main(){ 
    int& p = get_num(); // This is a compiler error. Can't create a non-const reference to an rvalue 
    const int& q = get_num(); // this will work. Can create const reference to an rvalue 
} 

Это часть стандарта C++.