QUIZ O - Solution.

Assume the following class declaration:

class X {
		int p; 
		...
	public:
		X( int p1 ) : p(p1) { ... }		// (a)
		X ( const X&  x1 ) { ... }              // (b)
		X& operator= (const X&  x2 ) { ... }    // (c)
		... // member functions etc.
		void merge ( X x3 ) { .... }            // (d)
	};

A line that begins with an X is a declaration of one or more new objects of type X (the same is true for any other type specifier, e.g. int or string). Consequently, one of the class constructors is called. Constructors (as well as C++ functions in general) can be overloaded, that is, the ones with the same name but different argument lists are considered different, and the compiler decides which one to use for a particular function call by looking at the list of the actual arguments passed to the function, and comparing their arguments with those of the known function prototypes (all of this happens at compile time -- the C++ compiler deduces the types of all expressions in your program). Therefore, the right constructor to call is chosen by looking at the list of arguments it receives; if no arguments are given, the default constructor X() for the class is used (but see below).

X a( 10 ), a1( 100 );

Constructor (a) is called twice.

X b;

Illegal. This would call the constructor X(); However, it is not defined for class X . Had the constructor (a) not been defined, an automatically created default constructor would have been used, but in the presence of other constructors explicitly defined for X by the user this doesn't happen, and compilation fails with an error. An explicit definition of X() is needed to make this line legal.

X c = 12;

This calls constructor (a) with integer argument 12. Equivalent forms:   X c(12); and    X c = X(12);

X c1 = a1;

This calls the copy constructor (b). This decision is again based the type of the RHS, which is interpreted as the argument to the constructor. Please note that this line has nothing to do with the overloaded assignment operator=. Operator= can be used only when both LHS and RHS objects exist, while here c has yet to be created. Therefore this amounts to calling a constructor, and the type of the argument (class X) suggests (b).

X d( a );

A call to (b).

X e( 5, 18 );

Illegal. This would call a constructor X( int, int ). Since no such constructor is defined, the line is illegal.

cout << a.p + a1.p << endl;

Illegal. The member p is private in X, so it cannot be accessed via "dot" (aka the member selection operator).

a1 = a;

Overloaded assignment (c). Think of it as a1.operator=(a);

d.merge( a );

Calls method (d), but first a copy of object a needs to be created, so the copy constructor is called first. Had the argument to merge been declared as X& rather than X, there would be no need to call a copy constructor.

X arr[ 15 ];

Illegal. This would create an array of 15 elements of type X. Creating each of these means calling a constructor; since no argument for the constructor is in sight, the constructor X() would be called. Had X(int) not been defined, the automatically created default constructor X() would have been called 15 times, but for the present definition of class X this line produces and error. Define some X() explicitly to allow the creation of array arr.

X f = X( -1 ) * X ( -2 );

Illegal. Two calls to (a) create two temporaries of type X, and that is OK. But then an overloaded operator*( const X& ) is required to form a third temporary which is their ìproductî. Then the copy constructor (c) is called to create f and fill it from the third temp. As soon as creation of f is over, all three temporaries are destroyed. To make this legal, add the overloaded X operator* (const X& ). (Note that it returns X, an instance of class X, not a reference X& -- a temporary needs to be created in this method, to hold the internal data of the result of the operator*).


It is highly recommended that you try compiling and running small pieces of code that deal with construction of objects and temporaries, passing them as arguments to functions etc. The fraction class code is a good place to start. Try various changes to the code, and observe the results.