2009-04-02 7 views
15

Je ne comprends pas. J'ai regardé le code le code pendant trois heures et je ne peux pas voir le problème.Erreur "Aucun constructeur par défaut approprié disponible" dans Visual C++

La classe que je crée, appelée TwoDayPackage, est dérivée d'une classe appelée Package.

Voici comment je définissais le constructeur:

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

Voici comment je mets en œuvre le constructeur:

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; 
} 

Voici comment je l'utilise dans ma fonction principale. Je sais que ma liste d'arguments est assez longue, il y a une raison pour cela. Merci.

Répondre

23

utiliser: il

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; 
    } 
+2

Mais ce n'est pas un ctor par défaut, Dirk (il a dit doucement.) –

+0

Merci, ça marche maintenant. Quelqu'un pourrait-il expliquer pourquoi cela fonctionne, cependant? Je ne comprends pas comment il appelle le constructeur de la classe parent. Je pensais que ce que je faisais (appeler le constructeur des parents par lui-même fonctionnerait) merci – chustar

+1

C'est la syntaxe: la classe de base doit être appelée à partir de la liste d'initialisation. Si vous ne spécifiez pas, le compilateur pense que vous vouliez appeler le constructeur par défaut de la classe de base et donc le problème. – dirkgently

4

La réponse est celle de dirkgently. L'explication est la séquence d'initialisation en C++.

Lors de la construction d'une classe, toutes les classes de base sont construites en premier. Si vous fournissez un appel au constructeur dans la liste d'initialisation, il appelle le constructeur approprié. Si la classe de base n'apparaît pas dans la liste d'initialisation, elle sera construite par défaut. Tout cela se passe avant entrant dans le bloc constructeur (accolades).

22

Un ctor par défaut est celui qui peut être appelé sans arguments. Au moins avec ce code, vous n'avez pas un: un cteur par défaut soit a la signature

ClassName::ClassName(); 

ou tout argument doit avoir une valeur par défaut. Cela dit, le point de Dirk à propos de la syntaxe est correct; Si vous voulez appeler les classes parentes ctor, vous devriez le faire après ce deux-points.


@ La réponse de dirkgently montre la bonne syntaxe, mais nous allons étendre un peu. Vous avez deux classes

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

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

puis vous venir pour définir

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; 
} 

... mais cela ne fonctionne pas? Pourquoi? Fondamentalement, parce que ce que vous dites C++ n'a pas de sens: le Package::Package ne fait que nommer le ctor de la superclasse et ne rien faire avec. Vous pouvez créer un nouvel objet de paquet de classe en utilisant le nouvel opérateur ,

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

mais c'est toujours pas ce que vous voulez faire; ce que vous voulez est de dire à C++ de construire les parties Package de TwoDayPackage en utilisant cette liste d'arguments. Vous n'avez pas besoin d'avoir le nom complet, car le compilateur sait déjà ce qu'est la classe parente.

Vous pouvez également simplement attribuer des valeurs dans le ctor enfant, mais cela est inefficace, car cela oblige le compilateur à générer du code pour «plusieurs trajets dans le puits». Donc, C++ a une syntaxe spéciale où les initialiseurs sont placés après un deux-points, comme l'a montré Dirk.

Encore une chose: puisque vous êtes juste assigner un paramètre à plat de toute façon, vous pouvez dire

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) 
{ 
} 

Vérifiez this section du C++ FAQ Lite pour plus.

Questions connexes