2010-09-23 5 views
7

Gegeben 2 Klassen:Wie kann ich einen Kompilierungsfehler bei versehentlicher Konstruktion bekommen?

... 
class Grades{ 
public: 
    Grades(int numExams) : _numExams(numExams){ 
     _grdArr = new double[numExams]; 
    } 
    double GetAverage() const; 
    ... 
private: // The only data members of the class 
    int _numExams; 
    double *_grdArr; 
}; 

class Student{ 
public: 
    Student(Grades g) : _g(g){ 
    } 
... 
private: // The only data members of the class 
    Grades _g; 
}; 
... 

Und ein kurzes Hauptprogramm:

int main(){ 
    int n = 5; // number of students 
    Grades g(3); // Initial grade for all students 
    // ... Initialization of g – assume that it's correct 
    Student **s = new Student*[n]; // Assume allocation succeeded 
    for (int it = 0 ; it < n ; ++it){ 
      Grades tempG = g; 
      // ... Some modification of tempG – assume that it's correct 
      s[it] = new Student(tempG); 
    } 
// ... 
return 0; 
} 

Dieser Code funktioniert gut. Aber durch Tippfehler Fehler der Linie:

Grades tempG = g; 

hat sich geändert:

Grades tempG = n; 

und es geht immer noch die Zusammenstellung. Welche einfache Änderung kann ich im code (dem main() code) machen, um einen Kompilierungsfehler durch diesen Tippfehler zu bekommen?

+0

In diesem Kontext muss "new" nicht verwendet werden. Sie sollten lieber Stack-Variablen (automatische oder feste Lebensdauer) verwenden, keine Heap-Variablen (dynamische Lefetime-Variablen). Suche std :: vector nach. –

Antwort

22

Dies liegt daran, dass Grades einen Konstruktor mit einem einzigen Argument hat, der als Konvertierungskonstruktor fungiert. Ein solcher Konstruktor verwendet ein int-Argument und erstellt ein Objekt vom Typ Grades.

Daher ist die Kompilierung erfolgreich.

Machen Sie das consructor von 'Sorten' expliziten

explicit Grades(int numExams); 

Diese

Grades g = 2; 

nicht zulassen wird, sondern ermöglicht allen folgenden

Grades g = Grades(2) // direct initialization 

Grades g = (Grades)2; // cast 

Grades g = static_cast<Grades>(2); 

Grades g(2);   // direct initialization. 
+4

Es ist wirklich eine Schande, dass "explizit" nicht der Standard ist - Sie sollten sich vielleicht angewöhnen, es auf jedes einzelne Argument anzuwenden und nur dort zu entfernen, wo es sinnvoll ist, automatische Konvertierungen zu haben. – stusmith

+1

@stusmith: Überprüfen Sie die Abschlusskommentare von Daniel des Diskussionsthreads http://groups.google.co.in/group/comp.std.c++/browse_thread/thread/3e845e305474febe#. Er schlägt vor, dass, wenn C++ noch einmal entworfen werden sollte, es eine gute Chance gibt, dass alle Konstruktoren und Konvertierungsfunktionen standardmäßig "explizit" waren, aber ein Benutzer könnte das "implizite" machen. – Chubsdad

+0

explicit stoppt auch verkettete Konvertierungen. Nehmen wir an, Grades nahmen eine andere Klasse mit dem Namen Term und Term hatten einen Konstruktor, der int numPapers nahm, ohne explizit, Grade g = 2 würde kompiliert werden - 2 würde in Term und Term in Grade konvertiert werden, alles im Hintergrund. Explicit kommt wirklich zur Geltung, wenn Sie einen einzelnen Parameter für den Konstruktor verwenden. Wenn Ihr Konstruktor mehr als einen Parameter verwendet, verringern sich die Chancen für eine intentionale Konstruktion erheblich. – Carl

4

Fügen Sie den explicit Schlüsselwort an den Konstruktor:

explicit Grades(int ...) ... 
Verwandte Themen