[comp.lang.c++] nit picking questions

rfg@riunite.ACA.MCC.COM (Ron Guilmette) (04/12/89)

Sorry to trouble you all, but I am still trying to absorb the fine
points of this language.

Can one of the language lawers who frequent this group please take a
minute or two to answer a few simple legality questions for me.
I would appreciate it a lot.

I would like answers based either on cfront 2.0 or on the more abstract
notion of the "formal language" rules" as they are now.

------------------------------------------------------------------------
What should (or does) happen if a given class inherits multiple
new operators or multiple delete operators from multiple base
classes? (This question assumes that MI has been implemented).

Is it legal for an "operator new" to return anything other than
a type "void*" result?

Is it legal for an "operator new" to accept anything other than a
single argument of type "long"?  (By the way... why is the argument
type "long" rather than type "unsigned long"?)

Is it legal for an "operator delete" to return anything other than
type "void"?

Is it legal for a "global" operator delete to have a formal argument
list which consists of anything other than a single formal parameter
of type "void*"?

Is it legal for a "class-specific" operator delete method to have a formal
argument list which consists of anything other than a single formal
argument of type "pointer to C" where type "C" is the containing class
type?  (I also have to wonder why class-specific delete operators need
to have any "explicit" formal arguments.  Don't these operators get a
"this" pointer?)

Can a union have public, private and protected parts?

Can a union contain member functions?

Can a data member and a method member declared within the same
class have the same name?  If so, what does &class_name::member_name
yield in such cases.

If a data member is declared in a base class, can it be redeclared
as either data member or as a method member in a class derived from
the given base class?  If it can be redeclared  as a data member
in the derived class, must it be redeclared with the same data type?

(Do the same rules apply as for method members which are redeclared
in a derived class, i.e. can this mechanism be used to change the
visibility of of an inherited data member in the same way that
the visibility of method members may be modified, i.e. the way it
is described on page 4 of the 1987 workshop proceedings?)

If this kind of redeclaration is allowed, what would the expression
&class_name::member_name yield in such cases?

If a method member is declared in a derived class, can it be
redeclared in a derived class as a data member?

If this kind of redeclaration is allowed, what would the expression
&class_name::member_name yield in such cases?

Is it legal or illegal to try to take the address of an overloaded
method or function using the '&' operator?   Given a particular
overloaded function or method that you absolutely *must* get the
address of, is there any way of uniquely specifying a particular
one of the overloadings?  Specifically, is the following allowed
(or will it ever be)?

		&class_name::overloaded_method_name(int,int)

Is it legal to try to take the address of an overloaded operator
for a given class (e.g. &my_class::operator+) even if that operator
may have both unary and binary forms, so long as only one of these
two forms is actually defined for the given class?

Is it legal to declare a virtual method in a base class with a given
parameter profile and then to declare a (virtual or plain) method
with the same name but with a different parameter profile in a class
which is derived from the given class?  (GNU G++ thinks this is
illegal).  An example:

	class base {
	public:
		int method (int, int);
	};

	class derived : public base {
	public:
		int method (float, float);	// is this an error?
	};

Is there any acceptable way of getting at the address of a vtable for
a given class.
-- 
// Ron Guilmette  -  MCC  -  Experimental Systems Kit Project
// 3500 West Balcones Center Drive,  Austin, TX  78759  -  (512)338-3740
// ARPA: rfg@mcc.com
// UUCP: {rutgers,uunet,gatech,ames,pyramid}!cs.utexas.edu!pp!rfg

bs@alice.UUCP (Bjarne Stroustrup) (04/12/89)

***> Ron Guilmette writes:
Sorry to trouble you all, but I am still trying to absorb the fine
points of this language.

Can one of the language lawers who frequent this group please take a
minute or two to answer a few simple legality questions for me.
I would appreciate it a lot.
***> Simple? :-)

I would like answers based either on cfront 2.0 or on the more abstract
notion of the "formal language" rules" as they are now.

------------------------------------------------------------------------
What should (or does) happen if a given class inherits multiple
new operators or multiple delete operators from multiple base
classes? (This question assumes that MI has been implemented).
***> The usual algorithm for detecting ambiguities in a class lattice
	(see the evolution paper) is applied and if there is exactly
	one delete operator you use it; otherwise you have a compile
	time error.

Is it legal for an "operator new" to return anything other than
a type "void*" result?
***> No.

Is it legal for an "operator new" to accept anything other than a
single argument of type "long"?  (By the way... why is the argument
type "long" rather than type "unsigned long"?)
***> Yes. operator new can be overloaded (details ``real soon now'')

Is it legal for an "operator delete" to return anything other than
type "void"?
***> Yes. It can take an additional argument of type long (a size)

Is it legal for a "global" operator delete to have a formal argument
list which consists of anything other than a single formal parameter
of type "void*"?
***> Yes (as above)

Is it legal for a "class-specific" operator delete method to have a formal
argument list which consists of anything other than a single formal
argument of type "pointer to C" where type "C" is the containing class
type?
***> Yes (as above)

(I also have to wonder why class-specific delete operators need
to have any "explicit" formal arguments.  Don't these operators get a
"this" pointer?)
***> No. They are applied after destruction.

Can a union have public, private and protected parts?
***> No (though, this is being debated)

Can a union contain member functions?
***> Yes.

Can a data member and a method member declared within the same
class have the same name?  If so, what does &class_name::member_name
yield in such cases.
***> No.

If a data member is declared in a base class, can it be redeclared
as either data member or as a method member in a class derived from
the given base class?
***> Yes.

  If it can be redeclared  as a data member
in the derived class, must it be redeclared with the same data type?
***> No.

(Do the same rules apply as for method members which are redeclared
in a derived class, i.e. can this mechanism be used to change the
visibility of of an inherited data member in the same way that
the visibility of method members may be modified, i.e. the way it
is described on page 4 of the 1987 workshop proceedings?)
***> Yes (but what is a ``method member'' I don't remember putting
	such a beast into C++ :-)

If this kind of redeclaration is allowed, what would the expression
&class_name::member_name yield in such cases?
***> A pointer to the member found in class_name or its bases using the
	usual ambiguity resolution mechanism. Essentially the one from
	the most derived class.

If a method member is declared in a derived class, can it be
redeclared in a derived class as a data member?
***> No (assuming you mean in the same derived class). You can only
	overload functions.

If this kind of redeclaration is allowed, what would the expression
&class_name::member_name yield in such cases?
***> It isn't.

Is it legal or illegal to try to take the address of an overloaded
method or function using the '&' operator?   Given a particular
overloaded function or method that you absolutely *must* get the
address of, is there any way of uniquely specifying a particular
one of the overloadings?
***> Yes. See the reference manual section 8.9. Essentailly, you can
	only take the address of an overloaded function if the context
	uniquely identifies which version.

  Specifically, is the following allowed
(or will it ever be)?

		&class_name::overloaded_method_name(int,int)
***> no and no (that would be ambiguous with a call)

Is it legal to try to take the address of an overloaded operator
for a given class (e.g. &my_class::operator+) even if that operator
may have both unary and binary forms, so long as only one of these
two forms is actually defined for the given class?
***> Yes - even if they have both been declared.

Is it legal to declare a virtual method in a base class with a given
parameter profile and then to declare a (virtual or plain) method
with the same name but with a different parameter profile in a class
which is derived from the given class?  (GNU G++ thinks this is
illegal).  An example:

	class base {
	public:
		virtual int method (int, int);
	};

	class derived : public base {
	public:
		int method (float, float);	// is this an error?
	};

***> It is legal, but probably not what you want. The second method()
	hides the first one and do not redefine it (in the vtbl).
	Cfront thinks you made a mistake:

"", line 9: warning:  derived::method() hides virtual base::method()

Is there any acceptable way of getting at the address of a vtable for
a given class.
***> No.

-- 
// Ron Guilmette  -  MCC  -  Experimental Systems Kit Project
// 3500 West Balcones Center Drive,  Austin, TX  78759  -  (512)338-3740
// ARPA: rfg@mcc.com
// UUCP: {rutgers,uunet,gatech,ames,pyramid}!cs.utexas.edu!pp!rfg

ark@alice.UUCP (Andrew Koenig) (04/12/89)

In article <161@riunite.ACA.MCC.COM>, rfg@riunite.ACA.MCC.COM (Ron Guilmette) writes:
> 
> Sorry to trouble you all, but I am still trying to absorb the fine
> points of this language.

> Can one of the language lawers who frequent this group please take a
> minute or two to answer a few simple legality questions for me.
> I would appreciate it a lot.

I'll do my best.

> What should (or does) happen if a given class inherits multiple
> new operators or multiple delete operators from multiple base
> classes? (This question assumes that MI has been implemented).

You had better define a third operator new in the derived class
if you intend to use `new' to allocate any objects of that class.
Otherwise it's ambiguous and you'll get an error message.

> Is it legal for an "operator new" to return anything other than
> a type "void*" result?

No.

> Is it legal for an "operator new" to accept anything other than a
> single argument of type "long"?  (By the way... why is the argument
> type "long" rather than type "unsigned long"?)

Actually, the argument should be of type size_t.  It's long in
some present implementations but that'll change.

> Is it legal for an "operator delete" to return anything other than
> type "void"?

No.

> Is it legal for a "global" operator delete to have a formal argument
> list which consists of anything other than a single formal parameter
> of type "void*"?

No.

> Is it legal for a "class-specific" operator delete method to have a formal
> argument list which consists of anything other than a single formal
> argument of type "pointer to C" where type "C" is the containing class
> type?  (I also have to wonder why class-specific delete operators need
> to have any "explicit" formal arguments.  Don't these operators get a
> "this" pointer?)

Member operator delete has only a single argument, of type void*.
It isn't C* because by the time operator delete is called, the
memory in question no longer contains a C -- it has been destroyed.
Member operator new and delete functions are static, so they don't
have `this' available.

> Can a union have public, private and protected parts?

No.

> Can a union contain member functions?

No.

> Can a data member and a method member declared within the same
> class have the same name?  If so, what does &class_name::member_name
> yield in such cases.

You can't overload data members.  If you have a data member with
a given name, you can't have a function member with the same name.

> If a data member is declared in a base class, can it be redeclared
> as either data member or as a method member in a class derived from
> the given base class?  If it can be redeclared  as a data member
> in the derived class, must it be redeclared with the same data type?

Yes.  It need not be redeclared with the same type.

> (Do the same rules apply as for method members which are redeclared
> in a derived class, i.e. can this mechanism be used to change the
> visibility of of an inherited data member in the same way that
> the visibility of method members may be modified, i.e. the way it
> is described on page 4 of the 1987 workshop proceedings?)

> If this kind of redeclaration is allowed, what would the expression
> &class_name::member_name yield in such cases?

I don't have my workshop proceedings handy -- how about an
example of what you mean?

> If a method member is declared in a derived class, can it be
> redeclared in a derived class as a data member?

Yes.

> If this kind of redeclaration is allowed, what would the expression
> &class_name::member_name yield in such cases?

If class_name is the base class, it's the function.  If class_name
is the derived class, it's the data member.

> Is it legal or illegal to try to take the address of an overloaded
> method or function using the '&' operator?   Given a particular
> overloaded function or method that you absolutely *must* get the
> address of, is there any way of uniquely specifying a particular
> one of the overloadings?  Specifically, is the following allowed
> (or will it ever be)?
> 
> 		&class_name::overloaded_method_name(int,int)

It's almost legal.  For example, this works:

	struct X {
		void f(int);
		void f(double);
	};

	main()
	{
		void (X::*fp)(double) = X::f;
	}

However, it's illegal if I rewrite the declaration of fp this way:

		void (X::*fp)(double);
		fp = X::f;

> Is it legal to try to take the address of an overloaded operator
> for a given class (e.g. &my_class::operator+) even if that operator
> may have both unary and binary forms, so long as only one of these
> two forms is actually defined for the given class?

The answer to this is similar to the previous one -- you can use
an overloaded name as an initializer but usually not as an expression.
For instance, the following is legal:

	struct X {
		X operator+(const X&);
		X operator+();
	};

	main()
	{
		X (X::*fp)(const X&) = X::operator+;
	}

> Is it legal to declare a virtual method in a base class with a given
> parameter profile and then to declare a (virtual or plain) method
> with the same name but with a different parameter profile in a class
> which is derived from the given class?  (GNU G++ thinks this is
> illegal).  An example:
> 
> 	class base {
> 	public:
> 		int method (int, int);
> 	};
> 
> 	class derived : public base {
> 	public:
> 		int method (float, float);	// is this an error?
> 	};

Your example is legal, even if you insert `virtual' in the
definition of base::method.  However, because the signatures
of base::method and derived::method are different, the two
functions are effectively completely unrelated.  You should
get a warning about this, but it's legal if it's really what
you want to do.

> Is there any acceptable way of getting at the address of a vtable for
> a given class.

No -- at least no way that is guaranteed by the language definition
or that I would personally consider acceptable.  Some things are
just not intended to be known.
-- 
				--Andrew Koenig
				  ark@europa.att.com

diamond@diamond.csl.sony.junet (Norman Diamond) (04/13/89)

In article <9189@alice.UUCP> bs@alice.UUCP (Bjarne Stroustrup)
very kindly answers most of the questions that were asked by
Ron Guilmette.  If Mr. Stroustrup has time, please kindly try
to answer some of them again.

>Is it legal for an "operator delete" to return anything other than
>type "void"?
>***> Yes. It can take an additional argument of type long (a size)
What about the _return_ type?

>If a method member is declared in a derived class, can it be
>redeclared in a derived class as a data member?
>***> No (assuming you mean in the same derived class). You can only
>	overload functions.
Mr. Guilmette must have meant:
If a method member is declared in a _base_ class, can it be
redeclared in a derived class as a data member?
(method member == member function)

>If this kind of redeclaration is allowed, what would the expression
>&class_name::member_name yield in such cases?
>***> It isn't.
Probably it is, when the preceding question is corrected.  Isn't
the rule the same, finding the most derived type in the class lattice?

>Is it legal or illegal to try to take the address of an overloaded
>method or function using the '&' operator?   Given a particular
>overloaded function or method that you absolutely *must* get the
>address of, is there any way of uniquely specifying a particular
>one of the overloadings?
>***> Yes. See the reference manual section 8.9. Essentailly, you can
>	only take the address of an overloaded function if the context
>	uniquely identifies which version.
How do you provide the context?  Mr. Guilmette's suggestion (following)
seems very reasonable.

>  Specifically, is the following allowed
>(or will it ever be)?
>
>		&class_name::overloaded_method_name(int,int)
>***> no and no (that would be ambiguous with a call)
It would not be ambiguous.  & cannot be applied to the result of a
call.  More obviously, "int" cannot be an actual parameter of a call,
only an expression can be, but this does not help when a function
takes no parameters.

------ cut here and discard everything below this point. ------

>Can a union have public, private and protected parts?
>Can a union contain member functions?

Gee, I thought the most interesting unions are those of private parts,
one of which is a ...
Never mind.

Norman Diamond, Sony Computer Science Lab (diamond%csl.sony.jp@relay.cs.net)
  The above opinions are my own.   |  Why are programmers criticized for
  If they're also your opinions,   |  re-inventing the wheel, when car
  you're infringing my copyright.  |  manufacturers are praised for it?

bs@alice.UUCP (Bjarne Stroustrup) (04/14/89)

Norman Diamond writes

 > In article <9189@alice.UUCP> bs@alice.UUCP (Bjarne Stroustrup)
 > very kindly answers most of the questions that were asked by
 > Ron Guilmette.  If Mr. Stroustrup has time, please kindly try
 > to answer some of them again.

 > >Is it legal for an "operator delete" to return anything other than
 > >type "void"?
 > >***> Yes. It can take an additional argument of type long (a size)
 > What about the _return_ type?

Sorry. I shouldn't try answering questions at the end of a long hard day.

There is nothing in the language that prevents you from chosing a return
type, though it seems that all current implementations require void*.
The default operator delete() in the library is:

	void* operator delete(void*);
	void* operator delete(void*, long);

where `long' will be replaced by `size_t' as part of the ANSIfication.


 > >If a method member is declared in a derived class, can it be
 > >redeclared in a derived class as a data member?
 > >***> No (assuming you mean in the same derived class). You can only
 > >	overload functions.
 > Mr. Guilmette must have meant:
 > If a method member is declared in a _base_ class, can it be
 > redeclared in a derived class as a data member?

I thought that was one of the other questions. The answer to this last
question is, Yes, this is legal:

	struct A { int f(); };
	struct B : A { int f; };

 > (method member == member function)
I forgot that humor should be pre- or suffixed by a :-) in this forum :-)

But I was also making a semi-serious point. Referring to member
functions as `methods' makes some people believe they have a semantics
and/or implementation very similar to Smalltalk methods. That can cause
confusion. Also, some people use `method' to refer to all member functions
and others use `method' to refer to virtual functions only. Another source
of confusion.

 > >If this kind of redeclaration is allowed, what would the expression
 > >&class_name::member_name yield in such cases?
 > >***> It isn't.
 > Probably it is, when the preceding question is corrected.  Isn't
 > the rule the same, finding the most derived type in the class lattice?

Yes, given the declarations above B::f the integer member B::f.
	A::f will give you the function. Please remember we are talking
	language definition here and not about style. I would hope that
	examples like these will remain rare in real code.

 > >Is it legal or illegal to try to take the address of an overloaded
 > >method or function using the '&' operator?   Given a particular
 > >overloaded function or method that you absolutely *must* get the
 > >address of, is there any way of uniquely specifying a particular
 > >one of the overloadings?
 > >***> Yes. See the reference manual section 8.9. Essentailly, you can
 > >	only take the address of an overloaded function if the context
 > >	uniquely identifies which version.
 > How do you provide the context?  Mr. Guilmette's suggestion (following)
 > seems very reasonable.

It IS very reasonable, but I did give an alternative, and Andy Koenig in
a separate message gave an example of its use. Here is another example:

	void f();
	void f(int);
	// ...
	void (*pv)() = &f;	// gets void f();
	void (*pi)(int) = &f;	// gets void f(int);

 > >  Specifically, is the following allowed
 > >(or will it ever be)?
 > >
 > >		&class_name::overloaded_method_name(int,int)
 > >***> no and no (that would be ambiguous with a call)
 > It would not be ambiguous.  & cannot be applied to the result of a
 > call.  More obviously, "int" cannot be an actual parameter of a call,
 > only an expression can be, but this does not help when a function
 > takes no parameters.

You are right. One could key the analysis on the `int'. This would make
the syntax analysis of C++ even more horrid than it already is, but the
main point is that C++ already has a mechanism for expressing this so
why add mechanism?

 > ------ cut here and discard everything below this point. ------
 > 
 > >Can a union have public, private and protected parts?
 > >Can a union contain member functions?
 > 
 > Gee, I thought the most interesting unions are those of private parts,
 > one of which is a ...
 > Never mind.

I think C++ is an even better source of silly puns and jokes than C is :-)

rfg@riunite.ACA.MCC.COM (Ron Guilmette) (04/15/89)

In article <10161@socslgw.csl.sony.JUNET> diamond@diamond.csl.sony.jp (Norman Diamond) writes:
>In article <9189@alice.UUCP> bs@alice.UUCP (Bjarne Stroustrup)
>very kindly answers most of the questions that were asked by
>Ron Guilmette.  If Mr. Stroustrup has time, please kindly try
>to answer some of them again.

Yes please.

>
>>Is it legal for an "operator delete" to return anything other than
>>type "void"?
>>***> Yes. It can take an additional argument of type long (a size)
>What about the _return_ type?

Ditto!

>>If a method member is declared in a derived class, can it be
>>redeclared in a derived class as a data member?
>>***> No (assuming you mean in the same derived class). You can only
>>	overload functions.
>Mr. Guilmette must have meant:
>If a method member is declared in a _base_ class, can it be
>redeclared in a derived class as a data member?

Right.  I did make a mistake in phrasing my question.  What I did mean
(and what Mr. Diamond correctly realized) was: is the following legal:

	class base {
	public:
		int member (int i);
		base ();
	};

	class derived : public base {
	public:
		int member;			// legal ??
		derived ();
	};

	int test ()
	{
		derived derived_object;

		&dervied::member;		// what does this mean?
		&derived_object.member		// what does this mean?
	}


>>Is it legal or illegal to try to take the address of an overloaded
>>method or function using the '&' operator?   Given a particular
>>overloaded function or method that you absolutely *must* get the
>>address of, is there any way of uniquely specifying a particular
>>one of the overloadings?
>>***> Yes. See the reference manual section 8.9. Essentailly, you can
>>	only take the address of an overloaded function if the context
>>	uniquely identifies which version.
>How do you provide the context?  Mr. Guilmette's suggestion (following)
>seems very reasonable.
>>
>>		&class_name::overloaded_method_name(int,int)
>>***> no and no (that would be ambiguous with a call)

I don't see any problem with disambiguating such a notation and allowing
the compiler to conclude that this is (obviously) a "name" of a particular
overloaded function.  After all, one look at the "actual parameters" and
the compiler should be able to see that these are TYPES and not VALUES.

Anyway, this is not a terribly important issue because there is a way
(that I have just learned about from Stroustrup's reply above) to get
the address of a particular overloading of a function.

Unfortunately, the wording of section 8.9 of the reference manual leaves
something to be desired when it comes to spelling out precisely what
sorts of context information may or may not be used to disambiguate
an overloaded function name when the & operator is applied to it.

I have found through experimentation that the GNU g++ compiler does do
disambiguation of overloaded function names in many cases which are
not spelled out in the Reference Manual.  Specifically, it seems to
take into account:

	a)	the type of the pointer being assigned to (or initialized)
	b)	the type to which the value yielded by the & operator is
		(explicitly) casted,
	c)	the type expected for the given actual function parameter
		(when the value yielded by the & operator is passed as
		an actual parameter to a function.

Are all these possible disambiguation factors "legal" for a "standard
conforming compiler" to take into account when performing disambiguation
of overloaded function names?  Are there any others?

Note that when factor (c) above is used for disambiguation by the GNU g++
compiler, it is apparently possible for truly ambiguous things to slip
by without any errors being generated, e.g.:

-----------------------------------------------------------------------
overload function;
overload function_of_function;

void function (char c);
void function (float f);

typedef void (*ptr_to_function_of_char)(char);
typedef void (*ptr_to_function_of_float)(float);

void function_of_function (ptr_to_function_of_float);
void function_of_function (ptr_to_function_of_char);


int test ()
{
	function_of_function (function);	// ERROR - ambiguous
}
-----------------------------------------------------------------------

What does cfront 2.0 do with this?


-- 
// Ron Guilmette  -  MCC  -  Experimental Systems Kit Project
// 3500 West Balcones Center Drive,  Austin, TX  78759  -  (512)338-3740
// ARPA: rfg@mcc.com
// UUCP: {rutgers,uunet,gatech,ames,pyramid}!cs.utexas.edu!pp!rfg