2010-09-23 13 views
7

Given 2 klas:Jak mogę uzyskać błąd kompilacji przy przypadkowej konstrukcji?

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

, a krótki program główny:

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

Ten kod działa poprawnie. Ale przez typo pomyłkę wiersza:

Grades tempG = g; 

zmienił się:

Grades tempG = n; 

i nadal przechodzi kompilację. Jaką prostą zmianę mogę zrobić w kodzie (głównym() kodzie), aby uzyskać błąd kompilacji przez ten błąd literówki?

+0

Nie ma potrzeby używania "nowego" w tym kontekście. Powinieneś raczej preferować zmienne stosowe (zmienne automatyczne lub stałe), a nie sterty (zmienne dynamiczne). Wyszukaj std :: vector. –

Odpowiedz

22

Dzieje się tak dlatego, że klasy mają pojedynczy konstruktor argumentów, który działa jako konstruktor konwertujący. Taki konstruktor pobiera argument int i tworzy obiekt typu Grades.

Dlatego kompilacja powiodła się.

Dokonać consructor z 'stopnie' jawne

explicit Grades(int numExams); 

To uniemożliwi

Grades g = 2; 

ale pozwala wszystkim następującym

Grades g = Grades(2) // direct initialization 

Grades g = (Grades)2; // cast 

Grades g = static_cast<Grades>(2); 

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

Naprawdę szkoda, że ​​"wyraźny" nie jest domyślny - możesz chcieć nabrać nawyku stosowania go do każdego konkretnego argumentu i usuwać je tylko wtedy, gdy ma sens automatyczne konwersje. – stusmith

+1

@stusmith: Sprawdź komentarze do zamknięcia od Daniela z wątku dyskusji http://groups.google.co.in/group/comp.std.c++/browse_thread/thread/3e845e305474febe#. Sugeruje on, że gdyby C++ miało zostać ponownie zaprojektowane, istnieje duża szansa, że ​​wszystkie konstruktory i funkcje konwersji były domyślnie "jawne", ale użytkownik mógłby uczynić to "niejawnym". – Chubsdad

+0

jawnie zatrzymuje także powiązane konwersje. Załóżmy, że klasa wzięła inną klasę o nazwie Term i Term ma konstruktora, który zajął int numPapers, bez wyraźnego, klasy g = 2 będą kompilować - 2 zostaną przekształcone w Term i Term w Grade, wszystko w tle. Explicit naprawdę wchodzi w grę, gdy używasz pojedynczego parametru dla konstruktora. Jeśli twój konstruktor przyjmuje więcej niż jeden parametr, szanse na niezamierzoną konstrukcję znacznie maleją. – Carl

4

Dodaj słowa kluczowego explicit do konstruktora:

explicit Grades(int ...) ... 
Powiązane problemy