C++: Создание неинициализированной переменной заполнителя, а не объекта по умолчанию

Я перемещаюсь от Java до C++ прямо сейчас, и я испытываю некоторые затруднения каждый раз, когда наиболее часто используемое понятие в Java не отображается непосредственно в C++. Например, в Java я сделал бы что-то как:

Fruit GetFruit(String fruitName) {
    Fruit fruit;
    if(fruitName == "apple") fruit = new Fruit("apple");
    else if(fruitName == "banana") fruit = new Fruit("banana");
    else fruit = new Fruit("kumquat"); //'cause who really wants to eat a kumquat?

    return fruit;
}

Конечно, в C++ Fruit fruit; оператор на самом деле создает фрукт. Это означает, что у меня должен быть конструктор по умолчанию? Это кажется небезопасным! Что, если моих фруктов по умолчанию оставляют?

7
задан JnBrymn 20 July 2010 в 15:31
поделиться

7 ответов

C++ дает вам гораздо больше головной боли, когда дело доходит до создания фруктов. В зависимости от ваших потребностей, вы можете выбрать один из следующих вариантов:

1) создать фрукт на стеке и вернуть копию (вам нужен конструктор копий), затем и обязательно предоставить какой-нибудь фрукт по умолчанию на случай, если имя не совпадет:

Fruit GetFruit(const std::string &name)
{
   if ( name == "banana" ) return Fruit("banana");
   if ( name == "apple" )  return Fruit("apple");
   return Fruit("default");
}

2) создать фрукт на куче и позаботиться о том, что может быть возвращен нулевой указатель, а также не забыть удалить этот фрукт где-нибудь и позаботиться о том, чтобы он был удален только один раз и только его владельцем (и позаботиться о том, чтобы ни у кого не было указателя на удаленный фрукт):

Fruit* GetFruit(const std::string &name)
{
   if ( name == "banana" ) return new Fruit("banana");
   if ( name == "apple" )  return new Fruit("apple");
   return NULL;
}

3) и, наконец, использовать умный указатель, чтобы избежать многих возможных проблем с указателями (но позаботиться о нулевых указателях). Этот вариант наиболее близок к вашему опыту программирования на Java:

typedef boost::shared_ptr<Fruit> FruitRef;

FruitRef GetFruit(const std::string &name)
{
   if ( name == "banana" ) return new Fruit("banana");
   if ( name == "apple" )  return new Fruit("apple");
   return FruitRef();
}
10
ответ дан 6 December 2019 в 08:13
поделиться

Объекты в Java представлены указателями. Поскольку это распространено, для указателей не существует специальной нотации. В C++ объекты могут быть представлены сами по себе или указателями,поэтому необходимо указывать указатели, когда они возникают.

Версия кода на C++:

Fruit * GetFruit(std::string fruitName) {
    Fruit * fruit = 0;
    if (fruitname == "apple") fruit = new Fruit("apple");
    else if (fruitname == "banana") fruit = new Fruit("banana");
    else fruit = new Fruit("kumquat");

    return fruit;
}

Возвращает указатель на Fruit. Вы можете получить доступ к таким членам, как fruit->color(), а не fruit.color(). Вы должны удалить этот указатель, когда вы закончите с ним.

7
ответ дан 6 December 2019 в 08:13
поделиться

Самым простым способом будет:

Fruit GetFruit(String fruitName) {
    if(fruitName == "apple") return Fruit("apple");
    else if(fruitName == "banana") return Fruit("banana");
    else fruit = return Fruit("kumquat"); //'cause who really wants to eat a kumquat?
}

... и прямое отображение будет заключаться в использовании (желательно «умного») указателя:

auto_ptr<Fruit> GetFruit(String fruitName) {
    auto_ptr<Fruit> fruit;
    if(fruitName == "apple") fruit = new Fruit("apple");
    else if(fruitName == "banana") fruit = new Fruit("banana");
    else fruit = new Fruit("kumquat"); //'cause who really wants to eat a kumquat?
    return fruit;
}
3
ответ дан 6 December 2019 в 08:13
поделиться

Чтобы сопоставить пример с C++, следует использовать указатель. В C++ построенный объект считается допустимым объектом (поэтому со ссылкой нельзя иметь значение null).

Использование Фрукты* фрукты = 0; ...

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

1
ответ дан 6 December 2019 в 08:13
поделиться

В C ++ есть указатели, которые неявны в Java: существует разница между объектом (то есть сущностью в памяти) и его адресом. В Java вам нужно явно создать объект, потому что, когда вы пишете

MyClass name;

, вы создаете ссылку для объекта этого класса. Это означает, что имя идентифицирует небольшой участок памяти, который содержит реальный адрес объекта. Когда вы строите весь дом, используя new, он возвращает только адрес, назначенный этой небольшой ячейке памяти.

В C ++ есть лучший контроль над памятью, и у вас есть 2 способа создания объекта: если вы используете оператор

MyClass object;

Этот объект создается в стеке. Это означает, что когда функция возвращается, объект уничтожается. Обратите внимание, что объект создается автоматически без использования оператора new. Если вы хотите, чтобы объект продолжал уничтожение стека, вы должны использовать оператор new, который возвращает указатель на вновь созданный объект:

MyClass *objectPtr = new MyClass();

Знак *, помещенный после имени класса, означает, что вместо этого вы запрашиваете относительный тип указателя. размещения этого объекта.

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

delete objectPtr;

Итак, вы можете сделать так:

MyClass *yourfunction(bool param) {
    if (param)
        return new MyClass(A);
    return new MyClass(B);
}

В любом случае вы должны знать, что указатели совсем не безопасно! Предоставление пользователю контроля над указателями может привести к плохому коду, неправильным действиям и многим вещам, которые совсем не хороши. Непосредственный пример: что, если вы забудете очистить память после использования объекта?)

В этом случае лучше если вы используете умные указатели, но сейчас действительно слишком много, чтобы сказать :) Наслаждайтесь поиском в Google!

HIH

1
ответ дан 6 December 2019 в 08:13
поделиться

Объекты работают несколько иначе в Java и в C ++. Как вы отметили, в вашем коде вы по умолчанию создаете объект, а затем рискуете, что он будет передан позже. Чтобы внести минимальное количество изменений в ваш код:

Fruit GetFruit(std::string fruitName) {
    if(fruitName != "apple" && fruitName != "banana")
    {
        fruitName = "kumquat";
    }
    return Fruit(fruitName);
}

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

Чтобы быть более Java-подобным, вы должны вместо этого использовать boost :: shared_ptr . Затем вы имеете дело с объектом с подсчетом ссылок, как и в Java:

boost::shared_ptr<Fruit> GetFruit(std::string fruitName) {
    if(fruitName != "apple" && fruitName != "banana")
    {
        fruitName = "kumquat";
    }
    return new Fruit(fruitName);
}
0
ответ дан 6 December 2019 в 08:13
поделиться

Ваша переменная fruit в Java примерно сопоставляется с указателем C++. Вы правы, вы не хотите создавать объект в стеке, вам просто нужен указатель на новый объект, который вы создаете. Поэтому, если вы просто измените Fruit на Fruit*, это сработает (если вы также измените тип возвращаемой функции). Просто помните, что вы должны позже удалить указатель, который вы вернули из этой функции, нет сборки мусора для очистки вашего news.

0
ответ дан 6 December 2019 в 08:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: