Constructor Argument List Question

N

Nosophorus

Hi!

I have coded a class and I would like to use default parameters in its
constructor argument list. So, let's suppose my class is:

class Class1 {
public:
Class1(int);
~Class1();
void print();
private:
/*SOME CODE HERE*/
};

Let's define the constructor as follows:

Class1::Class1(int dummy = 0)
{
/*SOME CODE HERE*/
}

Then, when I define an object of that class and call its constructor
with an empty list of arguments ( I mean "Class1 MyObj1()" ), the
compiler does not complain -- I should state that I call the
constructor using an empty argument list because I have in my mind
that, since the constructor has default parameter in its argument
list, when the constructor sees an empty list of arguments, it will
use the default parameter instead.

BUT, if I try to call a member function of that class (say
"MyObj1.print()" ), the compiler says the function is of non-class
type!

HOWEVER, if I define the object this way:

Class1 MyObj1;

The code works well! The constructor uses its default parameters and
the object defined can call any member function.

What are the differences between the two definitions above?

Defining an object through "Class1 MyObj1()" mean that a "void" value
is being passed to the constructor (which, in this case, requires an
"int" value)? What is the meaning of "Class1 MyObj1" ?

NEVERTHELESS, when I tried a different constructor argument list using
"void" instead of any other value, I got the same errors as cited
above when calling member functions!

class Class1 {
public:
Class1(void) {}; //OR Class1() {};
~Class1();
void print();
private:
/*SOME CODE HERE*/
};

Class1 MyObj1(); //OR Class1 MyObj1(void);
MyObj1.print(); <-- Gives an error! ('print' in 'MyObj1', which is of
non-class type Class1)

Sorry for the long question, but I hope I made me clear.

I appreciate any comments and further help.

Thank You!

Marcelo de Brito
 
I

Ian Collins

Nosophorus said:
Hi!

I have coded a class and I would like to use default parameters in its
constructor argument list. So, let's suppose my class is:

class Class1 {
public:
Class1(int);

The default value belongs here, not in the definition.

Class1( int = 0 );
~Class1();
void print();
private:
/*SOME CODE HERE*/
};

Then, when I define an object of that class and call its constructor
with an empty list of arguments ( I mean "Class1 MyObj1()" ), the
compiler does not complain

You are not declaring an object of that class, you are declaring a
function returning an instance of that class.
-- I should state that I call the
constructor using an empty argument list because I have in my mind
that, since the constructor has default parameter in its argument
list, when the constructor sees an empty list of arguments, it will
use the default parameter instead.
Well that's just wrong thinking.
BUT, if I try to call a member function of that class (say
"MyObj1.print()" ), the compiler says the function is of non-class
type!

A function doesn't have member functions!
HOWEVER, if I define the object this way:

Class1 MyObj1;

The code works well! The constructor uses its default parameters and
the object defined can call any member function.
As it should.
 
D

DerTopper

[snipped problem about statement that was meant to be a constructor
call but actually was a definition of a function]
Marcelo de Brito

Congratulations, you've tripped over one of the many obstacles that C+
+ can dish out. Admittedly, if you have the following class,
class ExampleClass
{
public:
ExampleClass ();
ExampleClass (int);
};

then you'd expect that if the statement
ExampleClass Instance (42);
calls the constructor of ExampleClass with an int argument, then
ExampleClass Instance ();
would be a call to the constructor taking no argument.
Unfortunately, this is not the case (as Ian already pointed out).

What can we learn from this?

There are a lot of things that make it hard to use C++ (as well as
Java or other languages that have similiar syntax). Above problem
could be avoided if the designers of C++ had chosen that function
definitions must be have the keyword "void" if the defined function
takes no argument. In that can your statement would exactly mean what
you had in mind (besides the "void" keyword doesn't hurt much). Of
course, one could argue that this doesn't fit with the scheme for
defining function parameters, but I think this exception to the rule
wouldn't be too bad.

If you have found this obstacles, beware of the following:
class ExampleClass
{
public:
void Method ();
};
class DerivedClass : public ExampleClass
{
public:
void Method (int);
};
void func ()
{
DerivedClass Instance;
Instance.Func ();
}

The call "Instance.Func ()" gives a compiler error. Figure it out for
yourself.

Regards,
Stuart

PS: Maybe we can add a section "Common Pitfalls" to the C++ FAQ? There
are a lot of cases where users complain about "unexpected" behaviour
of C++. Maybe you can find some more.
 
N

Nosophorus

Hi, Stuart!

Thank you very much for the useful reply.

I tried what you said and what I verified is that, if there is a class
holding two constructors like this:

class MyClass {
public:
MyClass1();
MyClass1(int = 0);
void print();
};

When an object is created this way:

MyClass MyObj;

The compiler says there is an overloaded call and an ambiguity too.

HOWEVER, if an "object" (it is not actually an object, but a function
as Ian said earlier) is defined as follows:

MyClass MyObj();

The compiler does not complain! BUT, trying to call a member function
(say "MyObj.print()" ) results in an error:

error: request for member ‘print’ in ‘MyObj’, which is of non-class
type ‘MyClass ()()’

NEVERTHELESS, if the object is created through this another way
(calling the other constructor):

MyClass MyObj(10);

Everything runs well! There is no problem when calling member
functions too!

It seems a little strange. :)

Thank You!

Marcelo de Brito
 
N

Nosophorus

Hi, Victor!

Thank you very much for your reply.
Why would it complain? No constructor is involved in declaring a
function like that.

Yes. It is a function and not an object -- I said it above --, so it
is not possible to call any member function.
Well, duh!

Well, Duh! :)
Why? There is no ambiguity when you actually provide an argument - the
compiler knows to call the constructor that does have an argument. The
default value ('0') declared for that argument does not matter.

What I consider a little strange is the, let's say, "inability" of C++
to declare an object that passes a "void" argument to the constructor,
even though the constructor definition is made to take a "void".
Trying to do it would mean a function definition and not an object (as
I stated above). Maybe it has to do with the C++ standards and so on.

Thank You!

Marcelo de Brito
 
J

James Kanze

[...]
What I consider a little strange is the, let's say,
"inability" of C++ to declare an object that passes a "void"
argument to the constructor, even though the constructor
definition is made to take a "void".

There is no such thing as a void argument. A constructor (or
any other function, takes 0 arguments, or it takes 1 argument,
or it takes 2 arguments, or... In certain cases, it can take "n
or more" arguments (when the parameter list ends with "...").
But an argument must be either a "value" or a reference, and
there are no void values, nor references to void.

In the case of default arguments, overload resolution behaves as
if there were 2 different functions declared: one with the
parameter, and one without. Thus, given:

void f() ;
void f( int = 0 ) ;

overload resolution considers the second as two functions,
f(int) and f(). And of course, anytime f() makes it into the
list of viable functions, it will be ambiguous with the first f.
Trying to do it would mean a function definition and not an
object (as I stated above).

Trying to do what? The ambiguities between function
declarations and object definitions with direct initializers is
well known (and very irritating), but it has nothing to do with
overload resolution. (And it only affects declarations.
There's no problem in other contexts, e.g. new ObjectType().)
 
V

Vidar Hasfjord

[...]
What I consider a little strange is the, let's say, "inability" of C++
to declare an object that passes a "void" argument to the constructor,
even though the constructor definition is made to take a "void".
Trying to do it would mean a function definition and not an object (as
I stated above). Maybe it has to do with the C++ standards and so on.

Your terminology is wrong as James Kanze points out. There is no void
argument. But I guess "void" is just your way of saying "no argument".
Use the latter.

As you have discovered, this is an embarrassing syntactical ambiguity
and one of the common pitfalls in C++. Search the web for "C++ most
vexing parse".

The C++ standard body has since worked hard for a new unambiguous and
regular initialization syntax. In C++0x you will be able to
consistently initialize using curly braces:

Foo fun1 (); // Function with no args returning object.
Foo obj2 {}; // Object init. with empty constructor argument list.

Foo fun2 ((int) f); // Function with a int arg.
Foo obj2 {(int) f}; // Object init. with a single arg casted to int.

Foo fun3 (Foo (f)); // Function with a Foo arg.
Foo obj3 {Foo (f)}; // Object init. with a Foo arg.

Regards,
Vidar Hasfjord
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,744
Messages
2,569,479
Members
44,900
Latest member
Nell636132

Latest Threads

Top