[comp.lang.c++] HELP: default constructor for array of class

chien@iitmax.iit.edu (Greg Chien) (05/02/91)

A beginner's question to C++ gurus:

When compiling the following program, C++ complains that Point::Point()
default constructor is not found in resolving Point p[2].  However,
if Point() { x = 200; } is uncommented, ambiguous constructors error
is generated in resolving Point q.  Both cases are tried with HP/C++ 2.1
and Borland C++.  What should be the right way to do?  Thanks in advance.

Greg Chien
Design Processes Laboratory
Institute of Design
Illinois Institute of Technology
chien@iitmax.iit.edu

// ---------------- 8< -------- CUT HERE ---------- 8< -----------------
#include <iostream.h>

class Point {
	int x;
public:
//	Point() { x = 200; }
	Point(int xc = 100) { x = xc; }
	GetX() { return x;}
};

int main()
{
	Point p[2];
	Point q;

	cout << p[1].GetX() << "\n";
	cout << q.GetX() << "\nO.K.\n";
	return 0;
}
// ---------------- 8< -------- CUT HERE ---------- 8< -----------------

cs132058@cs.brown.edu (Chris R. Brown) (05/03/91)

 
chien@iitmax.iit.edu (Greg Chien) writes:
>class Point {
>	int x;
>public:
>//	Point() { x = 200; }
>	Point(int xc = 100) { x = xc; }
>};

>When compiling the above program, C++ complains that Point::Point()
>default constructor is not found in resolving Point p[2].  However,
>if Point() { x = 200; } is uncommented, ambiguous constructors error
>is generated in resolving Point q.  Both cases are tried with HP/C++ 2.1
>and Borland C++.  What should be the right way to do?  Thanks in advance.

It turns out that the only way to specify arguments to the constructor
when instantiating a class array is inside a brace-enclosed array
initialization list:

	Point p[2] = { Point(50), Point(3), Point(20) };
OR	Point p[2] = { 50, 3, 20 };

(The second case can only be used if the constructor takes ONE argument.  
In that case, the integers will be interpreted as arguments to the 
constructor for Point, and Point's will be implicitly created and placed
in the array.)

In your case, in order to specify that the default parameter be used,
your code should read:

	Point p[2] = { Point(), Point(), Point() };

Now, this can get really awkward if your array size gets even moderately
large.  Some ways around this:

------------------------------------------------------------------------
1)  Create a class PointArray with a constructor that uses a loop
to send identical arguments to the Point class:

	class PointArray {
          private:
            Point **p;
          public:
            PointArray(int sz = DEFAULT) 
	    {
	      int i;
	      p = new Point *[sz];
	      for (loop=0; loop < sz; loop++)
		p[loop] = new Point();
	    }
	    :
     	}

This might not be worth it if you don't add any new functionality to the
array.
-------------------------------------------------------------------------
2)  Have two constructors for Point, one with 1 argument and the other w/
none:

	public:
	  Point() { x = DEFAULT }
          Point(int new_x) { x = new_x }

The reason the compiler got confused over your overloaded constructor is
that

>	Point() { x = 200; }
>	Point(int xc = 100) { x = xc; }

can both be interpreted as taking no arguments (for the second constructor,
if there is no argument, the default is used.
--------------------------------------------------------------------------

It seems odd that C++ would allow class arrays to be simply defined if the
constructor takes no arguments, as in
	public:
	    ClassX() { ... };
	:
	:
	ClassX arr[2];
but can't handle a class array w/ a constructor that DOES take arguments:
	public:
	    ClassZ(int n) { ... };
	:
	:
	ClassZ arr(3)[2];   // ERROR
The reason is that the preprocessor sees the parentheses as declaring some
sort of function called "arr" with a ClassZ return type.


- Chris R. Brown

///////////////////////////////////////////////////////////////////////////


	

steve@taumet.com (Stephen Clamage) (05/03/91)

chien@iitmax.iit.edu (Greg Chien) writes:

>When compiling the following program, C++ complains that Point::Point()
>default constructor is not found in resolving Point p[2].  However,
>if Point() { x = 200; } is uncommented, ambiguous constructors error
>is generated in resolving Point q.

>class Point {
>	...
>public:
>//	Point() { x = 200; }
>	Point(int xc = 100) { x = xc; }
>};
>	Point p[2];

A default constructor is required to initialize the array 'p'.  Under
the latest language rules, any constructor requiring no parameters
(such as 'Point(int=100);') will serve, but this is also noted as
a recent extension.  With future compilers, the could should work
as given.  With many current compilers (including Borland C++ 2.0)
the 'Point()' constructor is required, as that was the earlier rule.

But the combination
	Point();
	Point(int = 100);
is ambiguous, since neither constructor needs to be called with any
parameters.  You can achieve exactly the effect of your original code
by using
	Point() { x = 100; }
	Point(int xc) { x = xc; }
This satisfies both old and new language rules.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com