Проблема с C ++ в операторе if: создайте один из двух объектов - PullRequest
1 голос
/ 09 марта 2012

У меня есть домашнее задание, в котором у меня есть базовый класс Package и два производных класса, OvernightPackage и TwoDayPackage.В какой-то момент в проблеме мне нужно создать объект одного из этих двух типов, в зависимости от ввода пользователя.Это, очевидно, не работает:

        if (shippingOption == OVERNIGHT) {
            OvernightPackage packageObject( // Parameters entered here //);
        }

        else if (shippingOption == TWODAY) {
            TwoDayPackage packageObject( // Parameters entered here //);
        }

Как только эти операторы if выполняются, я вне этих объектов и не могу использовать packageObject. Этот пост помог мне понять, как я мог это сделать, если бы я просто создавал объект определенного типа с другими параметрами.Но требования к назначению состоят в том, что TwoDayPackage и OvernightPackage должны быть разными классами.

Как мне поступить (кроме того, что нужно делать с объектами в операторах if)?

РЕДАКТИРОВАТЬ: Спасибо за помощь в прояснении, все!

Ответы [ 5 ]

4 голосов
/ 09 марта 2012

Один из способов - использовать указатели:

    Package *packageObject = NULL;
    if (shippingOption == OVERNIGHT) {
        packageObject = new OvernightPackage( // Parameters entered here //);
    }

    else if (shippingOption == TWODAY) {
        packageObject = new TwoDayPackage( // Parameters entered here //);
    }
3 голосов
/ 09 марта 2012

Переменная типа A на самом деле не может быть производного типа, поэтому (как вы заметили) вы не можете просто объявить Package packageObject; и присвоить ей OvernightPackage или TwoDayPackage (они будут разрезаны).

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

2 голосов
/ 09 марта 2012

Код операции:

if (shippingOption == OVERNIGHT) {
    OvernightPackage packageObject( // Parameters entered here //);
}
else if (shippingOption == TWODAY) {
    TwoDayPackage packageObject( // Parameters entered here //);
}
// Presumably, process the package here.

Вы можете сделать это следующим образом, используя автоматическое распределение , что является абсолютно лучшим - самым простым, самым безопасным, самым эффективным - когда этоприменимо:

void process( Package const& package )
{
    // Process the package here.
}

void foo()
{
    // ... whatever, then:

    switch( shippingOption )
    {
    case overnight:
        process( OvernightPackage( blah ) );
        break;
    case twoDay:
        process( TwoDayPackage( blah ) );
        break;
    default:
        assert( false );    // Should never get here.
    }
}

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

typedef std::shared_ptr<Package> PackagePtr;

PackagePtr foo( blah, blah, arguments )
{
    // ... whatever, then:

    switch( shippingOption )
    {
    case overnight:
        return PackagePtr( new OvernightPackage( blah ) );
    case twoDay:
        return PackagePtr( new TwoDayPackage( blah ) );
    default:
        assert( false );    // Should never get here.
    }
}

Когда вы получаете больше опыта, вы должны стремиться всегда использовать для наиболее ограниченныхимеется интеллектуальный указатель, который может выполнять работу, например, std::unique_ptr.Потому что легко передать владение общему интеллектуальному указателю, но трудно вернуть его обратно в указатель владения.Однако, как новичок, вы обнаружите, что std::shared_ptr прекрасно работает для большинства вещей, которые в этом отношении похожи на картофель.; -)

2 голосов
/ 09 марта 2012

Ответ - указатели.

Package *packageConstructor(int type)
{
   switch (type) {
   case OVERNIGHT: return new OvernightPackage(/* ... */);
   case TWODAY: sleep(2 * 86400); /* :) :) :) */ return new TwoDayPackage(/* ... */);
   default: // unrecognized type: handle somehow: return NULL, or throw exception
   } 
}

Если у вас есть указатели, вам нужно беспокоиться о безопасности исключений. Лучше использовать какой-нибудь умный контейнер указателей вместо сырых указателей.

2 голосов
/ 09 марта 2012

Вроде так

#include <memory>
:::

std::unique_ptr<Package> package;

if(shippingOption == OVERNIGHT)
    package.reset(new OvernightPackage(params));
else if (shippingOption == TWODAY)
    package.reset(new TwoDayPackage(params));

package->member;
package->member_function();

Если у вас нет доступа к C ++ 11 (см. Ваш компилятор), вы всегда можете использовать boost::scoped_ptr или если вам действительно нужно std::auto_ptr. (если у вас есть gcc / g ++, попробуйте скомпилировать с -std = c ++ 0x)

Тогда преимущество такого способа перед другими перечисленными методами заключается в том, что память управляется семантикой RAII, что соответствует современному дизайну C ++.

http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization

http://en.cppreference.com/w/cpp/memory/unique_ptr

http://en.cppreference.com/w/cpp/memory/auto_ptr

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...