7

Given 2 classes:

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

And, a short main program:

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

This code works fine. But by typo mistake the line:

Grades tempG = g;

has changed to:

Grades tempG = n;

and still it passes the compilation. What simple change can i do in the code (the main() code) to get a compilation error by that typo mistake?

Chubsdad
  • 24,777
  • 4
  • 73
  • 129
Sanich
  • 1,739
  • 6
  • 25
  • 43
  • There is no need to use `new` in this context. You should prefer to use stack (automatic or fixed lifetime) variables not heap (dynamic lefetime) variables. Look up std::vector. – Martin York Sep 23 '10 at 12:31

2 Answers2

22

This is because Grades has a single argument constructor which acts as a converting constructor. Such a constructor takes an int argument and creates an object of type Grades.

Therefore the compilation is successful.

Make the consructor of 'Grades' explicit

explicit Grades(int numExams);

This will disallow

Grades g = 2;

but allows all of the following

Grades g = Grades(2)  // direct initialization

Grades g = (Grades)2; // cast

Grades g = static_cast<Grades>(2);

Grades g(2);          // direct initialization.
Chubsdad
  • 24,777
  • 4
  • 73
  • 129
  • 4
    It really is a shame that 'explicit' isn't the default - you might want to get into the habit of applying it to every single argument ctor, and only removing them where it makes sense to have automatic conversions. – stusmith Sep 23 '10 at 11:07
  • 1
    @stusmith: Check the closure comments from Daniel of the discussion thread http://groups.google.co.in/group/comp.std.c++/browse_thread/thread/3e845e305474febe#. He suggests that if C++ were to be designed once again, there is a good chance, that all constructors and conversion functions were "explicit" by default, but a user could make the "implicit". – Chubsdad Sep 23 '10 at 11:13
  • explicit also stops chained conversions. Suppose Grades took another class called Term and Term had a constructor that took int numPapers, without explicit, Grades g = 2 would compile - 2 would be converted into Term and Term into Grades, all in the background. Explicit really comes into its own when you use a single parameter for the constructor. If your constructor takes more than one parameter, chances of un-intentional construction reduce signifcantly. – Carl Sep 24 '10 at 06:01
4

Add the explicit keyword to the constructor:

explicit Grades(int ...) ...
Ivo
  • 3,481
  • 1
  • 25
  • 29