2012-02-05 5 views
1

Возможно ли инициализировать переменную из параметра return (по ссылке ref)? Скажем, у меня есть что-то вроде:C++ - Инициализировать переменную, передав ссылку на функцию?

Car c; // <- don't want to create a new Car here! 
if (findCar("beetle", c)) { 
    ... 
} 

где, если findCar успешно, она возвращает истину, и заполняет c:

bool findCar(string name, Car& out) { 
    ... 
    // return true if found 
    out = thecar; 
    return true; 
} 

Теперь мой класс автомобиля не имеет конструктора 0-аргумент, так что выше код не компилируется. Есть ли способ сохранить c неинициализированным до звонка до findCar?

Solutions Я думал, являются:

  • добавить дешевый конструктор 0-аргумент для автомобиля
  • переключатель к указателям (который я предпочел бы избежать)
+0

, почему вы хотите, чтобы избежать переключений к указателям? Это самый чистый путь. – akappa

ответ

4

Вид. Проблема в том, что ссылка абсолютно должна относиться к фактическому объекту. Итак, если вы вернетесь по ссылке, то кто-то должен создать объект для этой возвращенной ссылки.Поэтому, если вы не можете найти подходящий объект, не имеет смысла возвращать ссылку. Если вы передадите ссылку, то сначала необходимо создать объект, для аргумента, на который нужно ссылаться.

Вы можете обойти это, например, следующим образом:

Car &findCar(const string &name) { 
    ... 
    // return if found, else throw 
    if (found it) { 
     return thecar; // assuming `thecar` means some already-existing object, 
         // if it's a local variable then return by value! 
    } else { 
     throw std::runtime_error(name); 
    } 
} 

Caller делает:

Car c = findCar("beetle"); 

или Car &c = findCar("beetle");, если они хотят, чтобы «увидеть» фактический найденный объект, а не его копии , Если findCar хочет, чтобы вызывающие пользователи видели только копию, а не какой-то внутренний объект, то, конечно, вы можете вернуться по значению, а не по ссылке - разница в значении функции равна &.

И кто-то где-то должен обработать исключение.

Если вы предпочитаете избегать исключений, то правильная вещь для возврата из функции find является указателем (или другим итератором). Это то, что делают стандартные контейнеры и алгоритмы при поиске, и есть специальные значения (конечные итераторы, или вы можете использовать нулевые указатели), которые означают «не найден».

2

Всякий раз, когда изменяемый объект (который не является указателем или ссылкой), он содержит все данные объекта, а это значит, что он всегда должен быть инициализирован, поэтому да, вам придется использовать одно из предлагаемых вами решений.

Кстати, если вы не используете указатель или ссылку, вы также не можете хранить объекты производных классов в переменной, поэтому я бы предложил переключиться на указатели.

1

Объект инициализируется, как только вы объявляете их переменной.

Если вы хотите конце инициализации вы должны использовать указатель и:

Car *c; 

bool findCar(string name, Car * &out){ 
    ... 
    out = new Car(); 
} 

не забудьте удалить его

0

Нет, это невозможно. Если подпись параметра берет ссылку на автомобиль, то должен указать на объект автомобиля. У вас есть два решения только при наличии объекта, созданного на правом, как можно позднее время, использование указателей, как это:

car* find_car(string name) { 

    ... 
    return nullptr; 
} 

car* c = find_car(...); 
if (c != nullptr) { 
    ... 
} 

или использовать исключения, которые, вероятно, не то, что вы хотите

car find_car(string name) { 
    ... 
    throw new runtime_error("car not found"); 
} 

В принципе, объявление в качестве ссылочного означает, что вы гарантируете, что объект был сконструирован, чтобы это требовало требования. Я бы использовал указатели лично.

0

Вы можете вернуть Car из вашей функции:

struct Car 
{ 
    Car():_isValid(false){} 
    Car(const Car&); 
    bool isValid(); 
}; 

Car findCar (const string& name); 


Car car = findCar("beetle"); 
if (car.isValid()){ 
... 
} 

Другой вариант заключается в throw excpetion, если findCar не может найти любой автомобиль:

struct Car 
{ 
    Car(const Car&); 
}; 

Car findCar (const string& name) { 
    .... 
    if (noCarFound) throw CarNotFoundException(); 
    .... 
} 



try{ 
    Car car = findCar("beetle") { 

} 
catch (CarNotFoundException e) { 
    .... 
} 

Или создать Car конструктор, который принимает string

0

Я не очень опытен на C++, но также знаю, что это не самое чистое решение.

Однако здесь подход:

bool findCar(string name, Car **out) { 
    // first make out to null 
    *out = NULL; 
    ... 
    // if found 
    if(found){ 
     *out = &thecar; 
     return true; 
    } 

    // otherwise return false. Notice that out remains pointing null 
    return false; 
} 

Теперь в коде, вы должны иметь:

Car *c; // <- You don't create a new Car here! 
if (findCar("beetle", &c)) { 
    ... 
} 

Надеется, что вы найдете его полезным

Смежные вопросы