Нет подходящей ошибки конструктора по умолчанию в Visual C++

Я не понимаю. Я смотрю на код три часа и не вижу проблемы.

Создаваемый мной класс под названием TwoDayPackage является производным от класса Package.

Вот как я определил конструктор:

    TwoDayPackage(string, string, string, string, int, string, string, string, string, int, float, float, float);

Вот как я реализую конструктор:

TwoDayPackage::TwoDayPackage(string sName, string sAddress, string sState, string sCountry, int sZIP, string rName, string rAddress, string rState, string rCountry, int rZIP, float weight, float cost, float flat)
{
Package::Package(sName, sAddress, sState, sCountry, sZIP, rName, rAddress, rState, rCountry, rZIP, weight, cost);
flatRate = flat;
}

Вот как я использую его в своей основной функции.

TwoDayPackage pack2(senderName, senderAddress, senderState, senderCountry, senderZIP, receipientName, receipientAddress, receipientState, receipientCountry, receipientZIP, weight, cost, flat);

Я знаю, что мой список аргументов довольно длинный, и на это есть причина. Спасибо.


person chustar    schedule 02.04.2009    source источник


Ответы (3)


Следует использовать:

TwoDayPackage::TwoDayPackage(string sName, string sAddress, string sState, string  sCountry, int sZIP, string rName, string rAddress, string rState, string rCountry, int rZIP, float weight, float cost, float flat)
 :Package(sName, sAddress, sState, sCountry, sZIP, rName, rAddress, rState, rCountry, rZIP, weight, cost)
  {
    flatRate = flat;
   }
person dirkgently    schedule 02.04.2009
comment
Но это не актер по умолчанию, Дирк (мягко сказал он). - person Charlie Martin; 02.04.2009
comment
Спасибо, теперь работает. Может кто-нибудь объяснить, почему это работает? Я не понимаю, как он вызывает конструктор родительского класса. я думал, что я сделал (вызов конструктора родителей сам по себе сработает), спасибо - person chustar; 02.04.2009
comment
Таков синтаксис: базовый класс нужно вызывать из списка инициализаторов. Если вы не укажете, компилятор решит, что вы хотели вызвать конструктор базового класса по умолчанию, и, следовательно, проблема. - person dirkgently; 02.04.2009

Ctor по умолчанию — это тот, который можно вызывать без аргументов. По крайней мере, с этим кодом у вас его нет: ctor по умолчанию либо имеет подпись

ClassName::ClassName();

или каждый аргумент должен иметь значение по умолчанию.

Тем не менее, точка зрения Дирка о синтаксисе верна; если вы хотите вызвать ctor родительских классов, вы должны сделать это после этого двоеточия.


Ответ @dirkgently показывает правильный синтаксис, но давайте немного расширим его. У вас есть два класса

public class Package {
    // ...
    Package( /* that horrible ctor arg list */){/*...*/}
    // ...
}

public class TwoDayPackage : public Package {
    // ...
    TwoDayPackage(/* another horrible ctor */);  // declaration only
    // ...
}

И тогда вы приходите, чтобы определить его

TwoDayPackage::TwoDayPackage(string sName, string sAddress, 
                             string sState, string sCountry, 
                             int sZIP, string rName, 
                             string rAddress, string rState, 
                             string rCountry, int rZIP, 
                             float weight, float cost, float flat)
{

     Package::Package(sName, sAddress, sState, sCountry, sZIP, 
                      rName, rAddress, rState, rCountry, rZIP, 
                      weight, cost);
     flatRate = flat;
}

... но это не работает? Почему? По сути, потому что то, что вы говорите С++, не имеет смысла: Package::Package просто называет ctor суперкласса и ничего с ним не делает. Вы можете создать новый объект класса Package с помощью оператора new,

     Package foo = new
         Package::Package(sName, sAddress, sState, sCountry, sZIP, 
                          rName, rAddress, rState, rCountry, rZIP, 
                          weight, cost);

но это все еще не то, что вы хотите сделать; то, что вы хотите, — это сообщить C++, чтобы он конструировал части пакета TwoDayPackage, используя этот список аргументов. Вам не нужно иметь полное имя, потому что компилятор уже знает, что такое родительский класс.

Вы также можете просто присвоить значения в дочернем ctor, но это неэффективно, так как заставляет компилятор генерировать код для «многократных поездок в колодец». Итак, C++ имеет специальный синтаксис, в котором инициализаторы помещаются после двоеточия, как показал Дирк.

Еще одна вещь: поскольку вы все равно просто назначаете параметр квартире, вы можете сказать

TwoDayPackage::TwoDayPackage(string sName, string sAddress, 
                             string sState, string sCountry, 
                             int sZIP, string rName, 
                             string rAddress, string rState, 
                             string rCountry, int rZIP, 
                             float weight, float cost, float flat) :
    Package(sName, sAddress, sState, sCountry, sZIP, 
            rName, rAddress, rState, rCountry, rZIP, weight, cost),
    flatRate(flat) 
{
}

Дополнительную информацию см. в этом разделе C++ FAQ Lite.

person Charlie Martin    schedule 02.04.2009

Ответ таков: напрямую . Объяснением является последовательность инициализации в C++.

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

person David Rodríguez - dribeas    schedule 02.04.2009