Discussion:
Declarations that declare nothing
(too old to reply)
Fraser Ross
2008-06-24 17:01:06 UTC
Permalink
This compiles with BDS2006 but not with Comeau:

class {};

The lack of an error allows for other errors to not be reported, as in
QC report 49230. That report needs some commenting. I might write a
new report using the above statement add reference 49230.



The following program also shows that the lack of an error causes other
things to happen:

struct TM {
class {
unsigned __int8 Status;
unsigned __int8 Attribute;
};
};
[C++ Error] Unit2.cpp(9): E2019 'TM:: ::Status' cannot be declared in an
anonymous union
[C++ Error] Unit2.cpp(9): E2019 'TM:: ::Attribute' cannot be declared in
an anonymous union


Fraser.
Thomas Maeder [TeamB]
2008-06-24 20:08:08 UTC
Permalink
Post by Fraser Ross
The following program also shows that the lack of an error causes other
struct TM {
Thanks :-)
Post by Fraser Ross
class {
unsigned __int8 Status;
unsigned __int8 Attribute;
};
};
[C++ Error] Unit2.cpp(9): E2019 'TM:: ::Status' cannot be declared in an
anonymous union
[C++ Error] Unit2.cpp(9): E2019 'TM:: ::Attribute' cannot be declared in
an anonymous union
I don't quite follow. I agree that the term "union" in the error
message is a bit misleading, but what do you think is lacking"
Fraser Ross
2008-06-24 22:57:11 UTC
Permalink
"Thomas Maeder [TeamB]"
Post by Thomas Maeder [TeamB]
Post by Fraser Ross
class {
unsigned __int8 Status;
unsigned __int8 Attribute;
};
};
[C++ Error] Unit2.cpp(9): E2019 'TM:: ::Status' cannot be declared in an
anonymous union
[C++ Error] Unit2.cpp(9): E2019 'TM:: ::Attribute' cannot be
declared in
Post by Thomas Maeder [TeamB]
Post by Fraser Ross
an anonymous union
I don't quite follow. I agree that the term "union" in the error
message is a bit misleading, but what do you think is lacking"
It doesn't declare a class name or a object of a class. No matter what
the members are it declares nothing. Its ill-formed according to 7.0
point 3.

Fraser.
Thomas Maeder [TeamB]
2008-06-25 06:31:15 UTC
Permalink
Post by Fraser Ross
It doesn't declare a class name or a object of a class. No matter what
the members are it declares nothing. Its ill-formed according to 7.0
point 3.
Sure. But you get a diagnostic message, hinting at the anonymity of
the class, which probably is the error. This isn't perfect, but I have
seen worse :-)
Fraser Ross
2008-06-25 10:38:57 UTC
Permalink
"Thomas Maeder [TeamB]"
"Fraser Ross"
Post by Fraser Ross
It doesn't declare a class name or a object of a class. No matter what
the members are it declares nothing. Its ill-formed according to 7.0
point 3.
Sure. But you get a diagnostic message, hinting at the anonymity of
the class, which probably is the error. This isn't perfect, but I have
seen worse :-)
If it is made a struct instead of a class there isn't a diagnostic.
Even worse, the members can be accessed as if they are members of the
outer class:

struct TM {
struct {
unsigned __int8 Status;
unsigned __int8 Attribute;
};
void foo() {
Status=1;
};
};


Fraser.
Fraser Ross
2008-06-25 12:23:41 UTC
Permalink
struct {
unsigned char Status;
unsigned char Attribute;
} a;

Does this compile with the latest Builder compiler?

Fraser.
Alan Bellingham
2008-06-25 12:35:16 UTC
Permalink
Post by Fraser Ross
struct {
unsigned char Status;
unsigned char Attribute;
} a;
Does this compile with the latest Builder compiler?
In what context?

Comeau will complain about that at file scope, but not within a
function.

Alan Bellingham
--
Team Browns
ACCU Conference 2009: to be announced
Fraser Ross
2008-06-25 12:53:38 UTC
Permalink
I was expecting it to incorrectly compile at file scope with BCB. Can
you test that?

Fraser.
Alan Bellingham
2008-06-25 13:33:52 UTC
Permalink
Post by Fraser Ross
I was expecting it to incorrectly compile at file scope with BCB. Can
you test that?
I have BCB5 installed here. I'm assuming that's not useful to you.

Alan Bellingham
--
Team Browns
ACCU Conference 2009: to be announced
Fraser Ross
2008-06-26 20:06:52 UTC
Permalink
"Alan Bellingham"
"Fraser Ross"
Post by Fraser Ross
struct {
unsigned char Status;
unsigned char Attribute;
} a;
Does this compile with the latest Builder compiler?
In what context?
Comeau will complain about that at file scope, but not within a
function.
Comeau doesn't interpret 8.5 paragraph 9 as entirely as I do. Is it
necessary to insist on a user provided default constructor in certain
cases?


Fraser.
Alan Bellingham
2008-06-27 08:54:17 UTC
Permalink
Post by Fraser Ross
Post by Fraser Ross
struct {
unsigned char Status;
unsigned char Attribute;
} a;
Comeau doesn't interpret 8.5 paragraph 9 as entirely as I do. Is it
necessary to insist on a user provided default constructor in certain
cases?
In certain cases, but not in this.

It's not a non-POD type. It's not const-qualified. It gets an
indeterminate initial value. None of its sub-objects are
const-qualified.

I see no problem with the code as you supplied above, other than what
Comeau complains about when at file scope.

(And there, it complains that a's type does not have external linkage -
well, it has no name, so that's difficult - but that a itself does have
a name and does have external linkage.)

Alan Bellingham
--
Team Browns
ACCU Conference 2009: to be announced
Fraser Ross
2008-06-27 09:55:28 UTC
Permalink
"Alan Bellingham"
Post by Alan Bellingham
I see no problem with the code as you supplied above, other than what
Comeau complains about when at file scope.
I was thinking it was written like this at file scope:

struct A {
unsigned char Status;
unsigned char Attribute;
} const a;

Comeau now says it requires an initialiser. Since its got static
storage duration it shouldn't need an initialiser by how I interpret the
standards paragraph.

The word POD is not in the paragraph now. Do you have n2588.pdf?

Fraser.
Alan Bellingham
2008-06-27 11:00:46 UTC
Permalink
Post by Fraser Ross
struct A {
unsigned char Status;
unsigned char Attribute;
} const a;
Ah, now the type has a name, and you've made it const.
Post by Fraser Ross
Comeau now says it requires an initialiser. Since its got static
storage duration it shouldn't need an initialiser by how I interpret the
standards paragraph.
Aha.

para9 comprises two sentences. The first sentence applies to non-POD
structures (or, in n2588.pdf, 'non-trivial class type'). However, this
object isn't non-POD (it *is* trivial).

Therefore, we move on to see if the second sentence applies.

No initialiser has been supplied: the sentence applies. OK,
indeterminate state. Second half of sentence: it's const, so the program
is ill-formed, and the compiler should reject it.

Comeau is, as I read it, right.

Alan Bellingham
--
Team Browns
ACCU Conference 2009: to be announced
Fraser Ross
2008-06-27 11:24:31 UTC
Permalink
"Alan Bellingham"
Post by Alan Bellingham
Therefore, we move on to see if the second sentence applies.
No initialiser has been supplied: the sentence applies. OK,
indeterminate state. Second half of sentence: it's const, so the program
is ill-formed, and the compiler should reject it.
Comeau is, as I read it, right.
The object is at file scope with static storage duration. The second
sentence only applies to non-static objects.

Fraser.
Alan Bellingham
2008-06-27 11:42:03 UTC
Permalink
Post by Fraser Ross
"Alan Bellingham"
Post by Alan Bellingham
Therefore, we move on to see if the second sentence applies.
No initialiser has been supplied: the sentence applies. OK,
indeterminate state. Second half of sentence: it's const, so the
program
Post by Alan Bellingham
is ill-formed, and the compiler should reject it.
Comeau is, as I read it, right.
The object is at file scope with static storage duration. The second
sentence only applies to non-static objects.
Ah, interesting.

Here for reference is that para in the original standard:

"9 If no initializer is specified for an object, and the object is of
(possibly cv-qualified) non-POD class type (or array thereof), the
object shall be default-initialized; if the object is of const-
qualified type, the underlying class type shall have a user-
declared default constructor. Otherwise, if no initializer is
specified for an object, the object and its subobjects, if any,
have an indeterminate initial value90); if the object or any of
its subobjects are of const-qualified type, the program is
ill-formed."

I hadn't noticed the addition of the qualifier 'non-static' to the para
in n2588. According to ISO/IEC 14882:1998, Comeau is right. Assuming
that the para in n2588 is what the next standard will say, the behaviour
will have changed.

I don't have C++03 to hand, so I don't know whether the change is
between 98 and 03, or between 03 and 0X.

Alan Bellingham
--
Team Browns
ACCU Conference 2009: to be announced
Alan Bellingham
2008-06-27 11:45:28 UTC
Permalink
... and regarding the substance of the change, it's reasonable - the
object, if static, will end up zero initialised (according to para6),
and therefore not need any more initialisation, and therefore the lack
of an initialiser is not conceptually a problem.

Alan Bellingham
--
Team Browns
ACCU Conference 2009: to be announced
Fraser Ross
2008-06-27 11:48:28 UTC
Permalink
Post by Alan Bellingham
qualified type, the underlying class type shall have a user-
declared default constructor.
Theres a change here I've just noticed. "declared" is changed to
"provided" which presumably means defined. Comeau takes the meaning to
be declared I think.

Fraser.
Alan Bellingham
2008-06-27 12:23:34 UTC
Permalink
Post by Fraser Ross
Post by Alan Bellingham
qualified type, the underlying class type shall have a user-
declared default constructor.
Theres a change here I've just noticed. "declared" is changed to
"provided" which presumably means defined. Comeau takes the meaning to
be declared I think.
'defined' means you actually write out the function. 'declared' means
that it exists somewhere, and that's what actually matters for the
compilation (as opposed to linking) of the code.

The change to 'user-provided' here is because one of the features of
C++0X is that the user can now declare the default c'tor, without
actually providing it.

What am I on about? For example, take the following:

struct foo
{
std::string x;
};

The compiler will generate an automatic default c'tor (and copy c'tor,
and d'tor, and operator assignment). All well and good. Now add a useful
c'tor:

struct foo
{
foo(int);
std::string x;
};

The presence of the user-defined c'tor that takes an int means that the
default c'tor is *no longer* currently automatically generated. However,
it's annoying to make the user have to declare and define it just
because of that, so a new feature in C++0X is to allow the user to ask
the compiler to define it after all:

struct foo
{
foo(int);
foo() = default;
std::string x;
};

This means "give me the constructor that takes no arguments and generate
the definition it would have had".

(Not so useful for the default c'tor, or the d'tor, but it saves a lot
of annoyance with copy c'tors and assignment operators.)

The above *declares* the default c'tor, but the user isn't *providing*
it, the compiler is. Previously, anything declared by the user was
provided by the user. There's now a slight gap.

Alan Bellingham
--
Team Browns
ACCU Conference 2009: to be announced
Hendrik Schober
2008-06-27 13:53:21 UTC
Permalink
Post by Alan Bellingham
[...]
struct foo
{
foo(int);
foo() = default;
std::string x;
};
This means "give me the constructor that takes no arguments and generate
the definition it would have had".
(Not so useful for the default c'tor, or the d'tor, but it saves a lot
of annoyance with copy c'tors and assignment operators.)
Actually, I see it the other way around: I see some value
in this for a dctor, but why would I need this for dtor,
cctor und asop at all?
Post by Alan Bellingham
[...]
Alan Bellingham
Schobi
Alan Bellingham
2008-06-27 14:11:16 UTC
Permalink
Post by Hendrik Schober
Actually, I see it the other way around: I see some value
in this for a dctor, but why would I need this for dtor,
cctor und asop at all?
The compiler generated definition for a dctor or dtor is equivalent to
writing the name followed by empty braces. So

foo() = default;
~foo() = default;

is actually more typing than

foo() {};
~foo() {};

On the other hand, the default implementation of copy ctor or operator
assignment involves copying or assigning every member, which an inline
implementation with empty braces will not do.

Alan Bellingham
--
Team Browns
ACCU Conference 2009: to be announced
Hendrik Schober
2008-06-27 14:48:46 UTC
Permalink
Post by Alan Bellingham
[...]
The compiler generated definition for a dctor or dtor is equivalent to
writing the name followed by empty braces. So
foo() = default;
~foo() = default;
is actually more typing than
foo() {};
~foo() {};
The way I see it, the only reason this is needed at all is to
document that I haven't simply forgotten to implement such a
thing, but deliberately omitted it. For dtor, cctor, and asop
this is easy without this new syntax:

//~foo(); // default implementation used
//foo(const foo&); // default implementation used
//foo& operator=(const foo&); // default implementation used

Either I implement those, or I don't. For the dctor this is
different. And writing
foo() {}
doesn't say whether I have forgotten or deliberately omitted
to list the data members. So there, this syntax makes some
sense. (Well, I could still use a comment...)
Post by Alan Bellingham
[...]
Alan Bellingham
Schobi
Chris Uzdavinis (TeamB)
2008-06-27 17:00:40 UTC
Permalink
Post by Alan Bellingham
Post by Hendrik Schober
Actually, I see it the other way around: I see some value
in this for a dctor, but why would I need this for dtor,
cctor und asop at all?
The compiler generated definition for a dctor or dtor is equivalent to
writing the name followed by empty braces. So
foo() = default;
~foo() = default;
is actually more typing than
foo() {};
~foo() {};
True, but 2 things:

1) I don't like to put code in class
declarations. Ever. Not even an empty function like that. But
writing an out-of-class empty body is considerably more typing. If
you make it inline, it's even more typing.

2) The following:

struct foo
{
foo(const & foo) = default;
};

is *more* typing than

struct foo
{
};


That's what I don't get. The only value I see here is for default
constructors, but you did show that an empty body in the class is even
less typing. So now I'm not sure I see any reason to want these.

However, I am intrigued by the idea of the opposite:

struct foo
{
foo(const & foo) = delete; // do not generate
};
--
Chris (TeamB);
Chris Uzdavinis (TeamB)
2008-06-27 16:12:41 UTC
Permalink
Post by Alan Bellingham
The change to 'user-provided' here is because one of the features of
C++0X is that the user can now declare the default c'tor, without
actually providing it.
I haven't read anything substantial about this aspect of the new
standard, and so am only commenting based on what you said.

...
Post by Alan Bellingham
struct foo
{
foo(int);
std::string x;
};
The presence of the user-defined c'tor that takes an int means that the
default c'tor is *no longer* currently automatically generated.
Agreed.
Post by Alan Bellingham
However, it's annoying to make the user have to declare and define
it just because of that
Agreed.
Post by Alan Bellingham
so a new feature in C++0X is to allow the user to ask the compiler
struct foo
{
foo(int);
foo() = default;
std::string x;
};
Neat.
Post by Alan Bellingham
This means "give me the constructor that takes no arguments and generate
the definition it would have had".
(Not so useful for the default c'tor, or the d'tor, but it saves a lot
of annoyance with copy c'tors and assignment operators.)
In the normal class setting, I disagree, since those would be
generated without having to ask for them.

Maybe I'm being thick headed, but would you mind showing any example
where an explicitly "default" declared copy constructor somehow causes
a constructor to exist that otherwise would not have?
--
Chris (TeamB);
Duane Hebert
2008-06-27 17:34:48 UTC
Permalink
Post by Chris Uzdavinis (TeamB)
Post by Alan Bellingham
This means "give me the constructor that takes no arguments and generate
the definition it would have had".
(Not so useful for the default c'tor, or the d'tor, but it saves a lot
of annoyance with copy c'tors and assignment operators.)
In the normal class setting, I disagree, since those would be
generated without having to ask for them.
It's the behavior of blocking the default ctor when a
user defined ctor is created that bugs me.

About 12 minutes ago I added a ctor to a struct to assist in
initializing it and then got the compiler error (missing default ctor)
where I was putting it in the map.

I think the ctor() = default is OK but I would rather if the compiler
always generated the default ctor unless one was specified.
Alan Bellingham
2008-06-27 23:04:06 UTC
Permalink
Post by Duane Hebert
I think the ctor() = default is OK but I would rather if the compiler
always generated the default ctor unless one was specified.
Up till now, there's been no way of blocking that (proposed) behaviour.

Alan Bellingham
--
Team Browns
<url:http://www.borland.com/newsgroups/> Borland newsgroup descriptions
<url:http://www.borland.com/newsgroups/netiquette.html> netiquette
Duane Hebert
2008-06-30 12:34:18 UTC
Permalink
Post by Alan Bellingham
Post by Duane Hebert
I think the ctor() = default is OK but I would rather if the compiler
always generated the default ctor unless one was specified.
Up till now, there's been no way of blocking that (proposed) behaviour.
I'm not sure what you mean. What would be the down side
of creating a default ctor unless the user supplied one? I guess
you could have trouble for non pod struct/classes when using
std containers with a compiler supplied default ctor but that
would be a coding error.

Anyway, this syntax sounds OK.
Alan Bellingham
2008-06-30 12:52:56 UTC
Permalink
Post by Duane Hebert
I'm not sure what you mean. What would be the down side
of creating a default ctor unless the user supplied one?
The user might want to prohibit the ability to create such an object.

I have a number of object types that it does not make sense to create
with no parameters. For example - a class that disables a window for the
scope of a function, and then re-enables it at the end. It's a simple
enough class - on construction, it disables the window whose handle it
has been given. On destruction, it reenables it. If I have to add logic
code to cope with the possibility that there *is* no window handle when
the destructor is reached, it gets more complicated.

Alan Bellingham
--
Team Browns
ACCU Conference 2009: to be announced
Duane Hebert
2008-06-30 13:35:08 UTC
Permalink
Post by Alan Bellingham
Post by Duane Hebert
I'm not sure what you mean. What would be the down side
of creating a default ctor unless the user supplied one?
The user might want to prohibit the ability to create such an object.
I have a number of object types that it does not make sense to create
with no parameters. For example - a class that disables a window for the
scope of a function, and then re-enables it at the end. It's a simple
enough class - on construction, it disables the window whose handle it
has been given. On destruction, it reenables it. If I have to add logic
code to cope with the possibility that there *is* no window handle when
the destructor is reached, it gets more complicated.
But you're not likely to ever use the default ctor. If you
wanted to prevent this couldn't you just declare a private
default ctor?

I guess there are reasons but to me, the most general case
these days is that I have a ctor with args for initialization
and I want the object to go into standard containers so
I have to add the default ctors when I don't really use
them directly.

I suppose it serves as fodder for job interview
questions though.
Ed Mulroy [TeamB]
2008-06-30 16:59:17 UTC
Permalink
Post by Duane Hebert
I'm not sure what you mean. What would be the down side
of creating a default ctor unless the user supplied one?
...The user might want to prohibit the ability to create such
an object.
Put the constructor into the class' private area.

. Ed
Alan Bellingham
2008-06-30 18:28:48 UTC
Permalink
Post by Ed Mulroy [TeamB]
Put the constructor into the class' private area.
I do prefer the current situation though. It's annoying enough to have
to do that with the copy c'tor and assignment operator in such cases,
without having to do so with a default c'tor as well.

Alan Bellingham
--
Team Browns
ACCU Conference 2009: to be announced
Duane Hebert
2008-06-30 18:34:33 UTC
Permalink
Post by Alan Bellingham
Post by Ed Mulroy [TeamB]
Put the constructor into the class' private area.
I do prefer the current situation though. It's annoying enough to have
to do that with the copy c'tor and assignment operator in such cases,
without having to do so with a default c'tor as well.
I can see that. I think it's just a matter of taste. I prefer
to not have to create the default one when that's the normal
case.

The behavior that always confuses me is when someone
writes a dtor like:

~someObject() {}

I always wonder if it's replacing the default dtor. I know
it's not but then I wonder why it's not.
Fraser Ross
2008-06-30 22:35:05 UTC
Permalink
Post by Duane Hebert
Post by Alan Bellingham
Post by Ed Mulroy [TeamB]
Put the constructor into the class' private area.
Don't you mean the protected area?
Post by Duane Hebert
Post by Alan Bellingham
I do prefer the current situation though. It's annoying enough to have
to do that with the copy c'tor and assignment operator in such cases,
without having to do so with a default c'tor as well.
I can see that. I think it's just a matter of taste. I prefer
to not have to create the default one when that's the normal
case.
The behavior that always confuses me is when someone
~someObject() {}
I always wonder if it's replacing the default dtor. I know
it's not but then I wonder why it's not.
Has anything been gained by making a destructor protected? A protected
constructor prevents unwanted instantiation.

Fraser.
Duane Hebert
2008-06-30 23:50:26 UTC
Permalink
Post by Fraser Ross
Post by Duane Hebert
Post by Ed Mulroy [TeamB]
Put the constructor into the class' private area.
Don't you mean the protected area?
No. Alan implied that he wanted to prevent the default
ctor from being invoked. If it's protected it can be invoked
in a derived class.
Post by Fraser Ross
Post by Duane Hebert
The behavior that always confuses me is when someone
~someObject() {}
I always wonder if it's replacing the default dtor. I know
it's not but then I wonder why it's not.
Has anything been gained by making a destructor protected? A protected
constructor prevents unwanted instantiation.
None that I can think of at the moment but that's not
what I was referring to.
Ed Mulroy [TeamB]
2008-07-01 02:40:45 UTC
Permalink
Post by Fraser Ross
Post by Duane Hebert
Post by Ed Mulroy [TeamB]
Put the constructor into the class' private area.
Don't you mean the protected area?
I meant private

If what you want is no viable default constructor, asking for an addition to
the compiler is redundant. You can achieve it with all flavors of C++, even
that from 1990 by declaring it in the private area where nothing but a class
instance or item declared as a friend can access it.
Post by Fraser Ross
Has anything been gained by making a destructor protected? A
protected constructor prevents unwanted instantiation.
If protected it can also be invoked by an instance of a descendent class.
If private it cannot.
Post by Fraser Ross
Post by Duane Hebert
~someObject() {}
I always wonder if it's replacing the default dtor. I know
it's not but then I wonder why it's not.
As I understand it, if you provide a destructor then no other destructor
will be quietly provided by the compiler. If you do not provide a
destructor then the default one will be provided by the compiler. Therefore
you cannot supply a default constructor because you are not the compiler.

. Ed
Post by Fraser Ross
Post by Duane Hebert
Post by Ed Mulroy [TeamB]
Put the constructor into the class' private area.
Don't you mean the protected area?
Post by Duane Hebert
I do prefer the current situation though. It's annoying enough to
have to do that with the copy c'tor and assignment operator in
such cases without having to do so with a default c'tor as well.
I can see that. I think it's just a matter of taste. I prefer
to not have to create the default one when that's the normal
case.
The behavior that always confuses me is when someone
~someObject() {}
I always wonder if it's replacing the default dtor. I know
it's not but then I wonder why it's not.
Has anything been gained by making a destructor protected? A protected
constructor prevents unwanted instantiation.
Fraser Ross
2008-07-01 10:17:22 UTC
Permalink
"Ed Mulroy [TeamB]"
Post by Ed Mulroy [TeamB]
Post by Fraser Ross
Has anything been gained by making a destructor protected? A
protected constructor prevents unwanted instantiation.
If protected it can also be invoked by an instance of a descendent class.
If private it cannot.
I meant making the destructor protected instead of public. I can't
think of anything. An instantiation can be prevented by making the
constructors non-public. A non-public destructor can't do a job that is
already done.


Fraser.
Alan Bellingham
2008-07-01 10:37:34 UTC
Permalink
Post by Fraser Ross
I meant making the destructor protected instead of public.
Making a destructor protected is, in my experience, useful for one
thing, which is preventing deletion of the derived class by the pointer
to base.

(It's also a signal that your class isn't to be considered as a complete
object yet.)

If you want that, then the chances are that your base is some form of
'mix-in' class, providing functionality to the derived class, but not
being what the derived class is to be considered in the 'Is-A'
hierarchies.

For example, consider a drawing package. A circle may be derived
normally from a Shape, and therefore Is-A Shape. But it might also be
derived from Serialisable, which contains common code for writing the
object. Private derivation isn't appropriate, since you wish to be able
to call the write() method on your Circle, and also on, say, your
ColourPalette object (and a ColourPalette is obviously not a Shape). But
any code dealing with pointers to Serialisable probably shouldn't be
deleting those objects, and the easiest way to ensure that is to make
deletion through those pointers impossible.

Making a destructor private is a different thing - usually to be found
with COM-style AddRef/Release semantics.

Alan Bellingham
--
Team Browns
ACCU Conference 2009: to be announced
Fraser Ross
2008-07-01 14:45:12 UTC
Permalink
"Alan Bellingham"
"Fraser Ross"
Post by Fraser Ross
I meant making the destructor protected instead of public.
Making a destructor protected is, in my experience, useful for one
thing, which is preventing deletion of the derived class by the pointer
to base.
There is a reason then.

I'm not particularly impressed by the proposal N2326.

There are two methods that are used to make an abstract base class. One
is with a pure virtual function, usually the destructor. The other is
by making the constructors and destructor protected but there are
loopholes to that method such as friends.

Has nobody ever suggested a keyword to signify an ABC such as:

class abstractbase {
};

? If the constructors and destructor are implicitly protected then is
what is wanted without doing much typing.

If a polymorphic deletion is required a second keyword could imply a
public destructor:

class abstractbase polymorphicdestroy {
};

Fraser.
Duane Hebert
2008-07-02 00:36:08 UTC
Permalink
Post by Fraser Ross
There are two methods that are used to make an abstract base class. One
is with a pure virtual function, usually the destructor. The other is
by making the constructors and destructor protected but there are
loopholes to that method such as friends.
I think that there is only one way to make a class abstract and
that is to have it include a pure virtual function. Making the ctor
protected (or private BTW) doesn't prevent the class from being
instantiated. Check out the singleton pattern for example.
Post by Fraser Ross
class abstractbase {
};
I think the pure virtual function(s) idea is fine.
Post by Fraser Ross
? If the constructors and destructor are implicitly protected then is
what is wanted without doing much typing.
If a polymorphic deletion is required a second keyword could imply a
class abstractbase polymorphicdestroy {
};
??? I want polymorphic destruction to be automatic
as it is now with my virtual dtor. You know that you
don't need an abstract base class to have
polymorphic behavior? You just need to use
inheritance and a base class pointer. Or am I
just not following you?
Fraser Ross
2008-07-02 10:38:16 UTC
Permalink
Post by Duane Hebert
Post by Fraser Ross
class abstractbase {
};
I think the pure virtual function(s) idea is fine.
There is a cost to adding virtual functions. It doesn't look to me that
abstract classes were seen as important when C++ was invented.


I'd rather have a keyword that makes a class have the defaults I want
than have to write out all the special members. Most classes fall into
certain categories of use. This new syntax with default and delete is
orthogonal to access scope, as is friend declarations. Is anything
else?

Fraser.
Duane Hebert
2008-07-02 12:46:07 UTC
Permalink
Post by Fraser Ross
Post by Duane Hebert
Post by Fraser Ross
class abstractbase {
};
I think the pure virtual function(s) idea is fine.
There is a cost to adding virtual functions. It doesn't look to me that
abstract classes were seen as important when C++ was invented.
I'm having a hard time following your logic. You were talking about
abstract base classes. If I want an ABC, it's probably to use as
an interface and I don't see the utility of that without virtual functions.
In fact, I would consider an abstract base class without a virtual dtor
an error in most cases.
Post by Fraser Ross
I'd rather have a keyword that makes a class have the defaults I want
than have to write out all the special members. Most classes fall into
certain categories of use. This new syntax with default and delete is
orthogonal to access scope, as is friend declarations. Is anything
else?
I would prefer to have the default behavior more intuitive and
have the ability to override it when I intend to. As I said up thread,
I don't see why the default ctor is not created when a user supplied
NON default ctor is added. I think the compiler should supply a
default ctor unless the user supplies a default one.
Chris Uzdavinis (TeamB)
2008-07-02 13:18:22 UTC
Permalink
Post by Fraser Ross
There is a cost to adding virtual functions. It doesn't look to me that
abstract classes were seen as important when C++ was invented.
What definition of "abstract" are you using? Given your first
sentence, it sounds like like would like polymorphism without virtual
functions? Well, there is compile-time "static" polymorphism, but
it's a compmile-time polymorphism, with the morph only happening once,
when the program is built.
--
Chris (TeamB);
Fraser Ross
2008-07-02 14:01:13 UTC
Permalink
"Chris Uzdavinis (TeamB)"
"Fraser Ross"
Post by Fraser Ross
There is a cost to adding virtual functions. It doesn't look to me that
abstract classes were seen as important when C++ was invented.
What definition of "abstract" are you using? Given your first
sentence, it sounds like like would like polymorphism without virtual
functions? Well, there is compile-time "static" polymorphism, but
it's a compmile-time polymorphism, with the morph only happening once,
when the program is built.
I want to prevent a class from being used to create concrete objects
without having a pure virtual function. This is not for polymorphism.
Its only to aid the programmer. At present I can define the
constructors, destructor, asop and copy constructor with protected
access but that takes quite a lot of typing. If this for instance was a
recognised syntax I would have what I want:

class name protected {
};

Fraser.
Duane Hebert
2008-07-02 15:14:04 UTC
Permalink
Post by Fraser Ross
"Chris Uzdavinis (TeamB)"
"Fraser Ross"
Post by Fraser Ross
There is a cost to adding virtual functions. It doesn't look to me
that
Post by Fraser Ross
abstract classes were seen as important when C++ was invented.
What definition of "abstract" are you using? Given your first
sentence, it sounds like like would like polymorphism without virtual
functions? Well, there is compile-time "static" polymorphism, but
it's a compmile-time polymorphism, with the morph only happening once,
when the program is built.
I want to prevent a class from being used to create concrete objects
without having a pure virtual function. This is not for polymorphism.
Its only to aid the programmer. At present I can define the
constructors, destructor, asop and copy constructor with protected
access but that takes quite a lot of typing. If this for instance was a
class name protected {
};
You don't need to define them, just declare them.
Fraser Ross
2008-07-02 18:16:37 UTC
Permalink
"Duane Hebert"
Post by Duane Hebert
Post by Fraser Ross
I want to prevent a class from being used to create concrete objects
without having a pure virtual function. This is not for
polymorphism.
Post by Duane Hebert
Post by Fraser Ross
Its only to aid the programmer. At present I can define the
constructors, destructor, asop and copy constructor with protected
access but that takes quite a lot of typing.
You don't need to define them, just declare them.
That would mean there aren't any definitions and hence linking errors.

Fraser.
Chris Uzdavinis (TeamB)
2008-07-02 18:45:58 UTC
Permalink
Post by Fraser Ross
"Duane Hebert"
Post by Duane Hebert
Post by Fraser Ross
I want to prevent a class from being used to create concrete objects
without having a pure virtual function. This is not for
polymorphism.
Post by Duane Hebert
Post by Fraser Ross
Its only to aid the programmer. At present I can define the
constructors, destructor, asop and copy constructor with protected
access but that takes quite a lot of typing.
You don't need to define them, just declare them.
That would mean there aren't any definitions and hence linking errors.
There will only be linking errors if they are actually called, and
they're only called if a derived class is instantiated.

The copy ctor/assignment-op are not strictly necessary, but a means to
construct and destruct the object are. (The derived class constructor
and destructor will invoke them in the base, placing a requirement
that they be defined in the base.)
--
Chris (TeamB);
Duane Hebert
2008-07-02 19:06:26 UTC
Permalink
Post by Fraser Ross
"Duane Hebert"
Post by Duane Hebert
Post by Fraser Ross
I want to prevent a class from being used to create concrete objects
without having a pure virtual function. This is not for
polymorphism.
Post by Duane Hebert
Post by Fraser Ross
Its only to aid the programmer. At present I can define the
constructors, destructor, asop and copy constructor with protected
access but that takes quite a lot of typing.
You don't need to define them, just declare them.
That would mean there aren't any definitions and hence linking errors.
Only if you call it. I thought the idea was to prevent instantiation
of the class? Or are you saying that you want to make the default
ones protected? Sorry but I think I'm still missing your point.

When you say that you can define the operators as protected, that means
that you expect them to be used in a derived class. But to use them in
the derived class, you have to call them with the base class namespace.
Operators (at least assignment operators) and constructors aren't inherited.
Fraser Ross
2008-07-02 20:02:20 UTC
Permalink
"Duane Hebert"
Post by Duane Hebert
Only if you call it. I thought the idea was to prevent instantiation
of the class? Or are you saying that you want to make the default
ones protected? Sorry but I think I'm still missing your point.
I want to prevent instantiation of a base but allow instantiation of a
derived class.

class Base {
int member;
protected:
Base() {}
~Base() {}
Base(Base const &rhs) { member=rhs.member; }
Base & operator=(Base const &rhs) { member=rhs.member; }
void foo() {};
};


class Derived : private Base {
public:
void foo();
};

Outside code can't do anything unwanted with Base. This is a
is-implemented-in-terms-of relationship. I know containment is better
but it is more work when Base functions are to be public in Derived. I
had to define 4 special member functions in Base to make them provided
and protected.

Fraser.
Duane Hebert
2008-07-02 20:27:46 UTC
Permalink
Post by Fraser Ross
"Duane Hebert"
Post by Duane Hebert
Only if you call it. I thought the idea was to prevent instantiation
of the class? Or are you saying that you want to make the default
ones protected? Sorry but I think I'm still missing your point.
I want to prevent instantiation of a base but allow instantiation of a
derived class.
class Base {
int member;
Base() {}
~Base() {}
Base(Base const &rhs) { member=rhs.member; }
Base & operator=(Base const &rhs) { member=rhs.member; }
void foo() {};
};
class Derived : private Base {
void foo();
};
Outside code can't do anything unwanted with Base. This is a
is-implemented-in-terms-of relationship. I know containment is better
but it is more work when Base functions are to be public in Derived. I
had to define 4 special member functions in Base to make them provided
and protected.
Ok. But you're not using any of the protected functions
except foo() in the derived class. I suppose that you can call the others
using
Base:: syntax but I'm sure you don't think that your derived class
somehow now has your base class's assignment operator.
I mean your derived class will still have whatever the default asop is for
it.


I guess the problem that I have here is the documentation value.
If I see protected functions, I expect to be able to use them
in a derived class. If I see a pure virtual function, then I
know it is abstract.

Chris Uzdavinis (TeamB)
2008-07-02 13:15:54 UTC
Permalink
Post by Duane Hebert
Post by Fraser Ross
There are two methods that are used to make an abstract base class. One
is with a pure virtual function, usually the destructor. The other is
by making the constructors and destructor protected but there are
loopholes to that method such as friends.
I think that there is only one way to make a class abstract and
that is to have it include a pure virtual function. Making the ctor
protected (or private BTW) doesn't prevent the class from being
instantiated. Check out the singleton pattern for example.
That's true, but only to the extent that other code is a friend or
otherwise has access to the constructors. If you cannot access the
constructor at all, and cannot call code that has such access, the
class is "effectively" abstract, in that it's not instantiable.

The singleton pattern can work with an internal or external singleton
interface. The External interface is performed in a seperate class,
and it requires that requires that the constructor of its <T> object
is public, or that the it is a friend of <T> such that it can access
the constructor. Alternately, the singleton "interface" can be bolted
directly onto a class, exposing an "instance" method that internally
allocates an object.

Not that I'm a big fan of singletons. The more I use them, the less I
wish I had to! They make it very difficult to unit-test code and make
it hard to simulate two processes running in one. (Process A runs
normlly on one host, process B runs on another host, each has their
own singletons. But say you want to write a test that simulates
process A and B in one real process, by instantiating the tested
component twice. How do you make one object use one singleton and the
other object use the other?)

I haven't found a good solution to that other than to fork a child
process and marshal commuincations through pipes or sockets. A real
pain.
Post by Duane Hebert
??? I want polymorphic destruction to be automatic
as it is now with my virtual dtor. You know that you
don't need an abstract base class to have
polymorphic behavior? You just need to use
inheritance and a base class pointer. Or am I
just not following you?
... and virtual functions. :)
--
Chris (TeamB);
Duane Hebert
2008-07-02 15:10:27 UTC
Permalink
Post by Chris Uzdavinis (TeamB)
Post by Duane Hebert
Post by Fraser Ross
There are two methods that are used to make an abstract base class. One
is with a pure virtual function, usually the destructor. The other is
by making the constructors and destructor protected but there are
loopholes to that method such as friends.
I think that there is only one way to make a class abstract and
that is to have it include a pure virtual function. Making the ctor
protected (or private BTW) doesn't prevent the class from being
instantiated. Check out the singleton pattern for example.
That's true, but only to the extent that other code is a friend or
otherwise has access to the constructors. If you cannot access the
constructor at all, and cannot call code that has such access, the
class is "effectively" abstract, in that it's not instantiable.
I just meant that setting a ctor as private doesn't make the class
abstract as the ctor can still be invoked via a static function
such as with the singleton pattern.

BTW I have one or two singletons and while I'm not wild
about them, I haven't had time to refactor them either. As
for friends, I try not to use them either.
Hendrik Schober
2008-07-01 07:26:03 UTC
Permalink
Post by Duane Hebert
Post by Alan Bellingham
Post by Ed Mulroy [TeamB]
Put the constructor into the class' private area.
I do prefer the current situation though. It's annoying enough to have
to do that with the copy c'tor and assignment operator in such cases,
without having to do so with a default c'tor as well.
I can see that. I think it's just a matter of taste. I prefer
to not have to create the default one when that's the normal
case.
I can't decide on this issue. As an experienced C++
programmer, I don't see what the new syntax gains,
that we didn't have by declaring stuff private. As a
C++ teacher, I know that declaring stuff private
seems a very obscure technique to novices.
If there's any changes regarding the way we control
the creation of those special member functions (e.g.
dctor cctor, dtor, asop) by the compiler, I'd really
like to have a simple to remember and very obvious
to understand syntax for preventing it, plus the
elimination of the difference between the conditions
for automatic creation of the dctor and all the other
special member functions.
I've found that students have a hard time remembering
the latter and while they find that having to write
those functions in order to not to have them is a
rather strange and subtle way.
Post by Duane Hebert
[...]
Schobi
Alex Bakaev [TeamB]
2008-06-25 18:30:00 UTC
Permalink
Post by Fraser Ross
Does this compile with the latest Builder compiler?
Yes.
Loading...