Discussion:
Casting to base class
(too old to reply)
Marcos Boyington
2004-12-22 08:52:40 UTC
Permalink
Hey guys, quick question about how C++ designers chose to not implement
this, I'm sure there are some people here who can take a better guess at it
than I.

So, in C++, the only way to prevent typecasting to a base class is by having
private inheritance (correct?). However, this prevents one from doing 2
very important things:

Example #1: Allow conversion from child -> grandparent, but NOT child ->
parent.

Say we have a class structure such as this:
class AbstractionLayer
{};
class FunctionalityLayer : protectected AbstractionLayer
{};
template <typename _T>
class TypesafeLayer : private FunctionalityLayer
{};

We want to be able to cast to AbstractionLayer, but not to
FunctionalityLayer (this is an internal class which has funcitonality, but
we don't want usage of this class directly). However, we do want to
typecast to an AbstractionLayer.

Take, for example, a memory allocator. AbstractionLayer provides simple
allocation of memory, returning simply allocated memory and freeing
allocated memory. FunctionalityLayer provides the actual allocation of
memory: we could have, say, 2 types, a static allocator (allocates one big
chunk and asserts if we try to insert memory when it's full), and a growing
allocator (creates a linked list of memory chunks). Lastly, TypesafeLayer
would have 2 functions which are typesafe, and would do the appropriate
new() and ~ calls after allocating/deallocating memory. However, in the
example above, we are not allowed to typecast to AbstractionLayer.

Example #2: Limit typecasting but allow function usage

Say we have something similar to the above, i.e. a class with functionality.
We want these functions to be externally accessible to others, HOWEVER, we
do NOT want it to be typecasted to the base class. Sure we can do "using"
for all the functions, but this becomes a hassle if we add functionality, as
we have to modify both classes. Lastly, in a case such as this, we are left
with no options:

class FunctionalityLayer1 : protectected AbstractionLayer
{};
class FunctionalityLayer2 : protectected AbstractionLayer
{};
template <typename _FuncLayer>
class TypesafeLayer : private _FuncLayer
{};

Anyone know if they're planning to add support to overriding the "conversion
to a reference to a base class operator", or why it hasn't been done yet?
The above examples are shown below with this operator, if C++ were to
support this (it does not):

Example #1:
class AbstractionLayer
{};
class FunctionalityLayer : protectected AbstractionLayer
{};
template <typename _T>
class TypesafeLayer : private FunctionalityLayer
{
public:
operator AbstractionLayer& () { return *this; }
};

Example #2:
class FunctionalityLayer1 : protectected AbstractionLayer
{};
class FunctionalityLayer2 : protectected AbstractionLayer
{};
template <typename _FuncLayer>
class TypesafeLayer : private _FuncLayer
{
private:
operator _FuncLayer& () { return *this; }
};



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Falk Tannhäuser
2004-12-23 11:52:39 UTC
Permalink
Post by Marcos Boyington
So, in C++, the only way to prevent typecasting to a base class is by having
private inheritance (correct?).
Well, it doesn't totally prevent it, but just renders it private
(or protected, in case of protected inheritence).
Post by Marcos Boyington
However, this prevents one from doing 2
Example #1: Allow conversion from child -> grandparent, but NOT child ->
parent.
You can do this:

class AbstractionLayer {};
class FunctionalityLayer : protected AbstractionLayer {};

template <typename T> class TypesafeLayer : private FunctionalityLayer
{
public:
AbstractionLayer& to_AbstractionLayer() { return *this; }
AbstractionLayer const& to_AbstractionLayer() const { return *this; }
};

int main()
{
TypesafeLayer<int> tsli;
AbstractionLayer& a = tsli.to_AbstractionLayer();
AbstractionLayer* pa = &tsli.to_AbstractionLayer();
return 0;
}

Falk

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Ron Natalie
2004-12-25 10:11:31 UTC
Permalink
Post by Falk Tannhäuser
Post by Marcos Boyington
So, in C++, the only way to prevent typecasting to a base class is by having
private inheritance (correct?).
Well, it doesn't totally prevent it, but just renders it private
(or protected, in case of protected inheritence).
It twarts implicit conversion, but a C-style cast can still force
a conversion to even an inaccessible base class. It's the one
thing that a C-style cast will do that there is no C++ style cast
equivelent.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Marcutio B
2005-01-04 09:47:04 UTC
Permalink
Man, there were some good responses, but for some reason I don't see them on
this server, only on newsarch.com, but I'll try to answer them here.

#1) "and protected"
Yes that's correct, sorry, I probably should've mentioned that. I
figured it was implied :)

#2) "Your design is flawed"
Just because you've never used it, doesn't mean the design is flawed or
impractical :) It may seem strange at first, but there are plenty of C++
features that are also strange and may seem "flawed" or "impractical" if you
are not used to it (virtual inheritance, "using", member function pointer
(as opposed to a delegate), to name a few). Just because there isn't some
book showing you a design pattern with this, or just because the language
doesn't support it, doesn't mean there isn't some practical use to it.

#3) "Use virtual inheritance"
That was a good call, I'm not sure who made it. It doesn't solve ALL
the problems, but it does solve the "allow typecasting to grandparent but
not parent" dilemma. Of course, it requires modification of the parent
class to have virtual inheritance, which isn't the prettiest thing (I still
dislike how C++ requires virtual inheritance to be in the parent class
instead of the inheriting class, but I guess it's the simplest way to
implement). But it was a good suggestion, thanks!

#4) "Use a function called to_Something"
I probably should've mentioned that I had already considered this,
however, although this is a valid solution, it's not the prettiest (implicit
conversions are not only convenient, they help prevent errors)

In any case, I realize that there are a few valid workarounds, but this
doesn't mean that being able to override the "convert to base class
operator" is an invalid or impractical need. C++ is supposed to allow an
immense amount of flexibility, while at the same time being a safe language
which helps prevent errors during compile time. It happens quite often
that one wishes to have an inheriting class which has all of the
functionality of the parent (I.e. all the functions of the parent can be
called from the child), but the child is not typecasteable to the parent.
An example is inheriting from an STL class, which does not have a virtual
destructor, and so should not be typecast to the parent class (at least, not
implicitly, if you choose to force it, then like anything else in C++,
that's your own problem heh)

Of course you can work around this by having composition or "using" - I.E.
either have a member object instead of inheriting (and having calls which
reroute the functionality), or inherit privately and then do "using" on all
the functions to make them public again. But why? Anything can be "worked
around", including making C an OOP-like language. But C++ is supposed to
make things "easy". This is a valid usecase which is used often, and C++
allows us to override all other operators, except "convert to base class" -
again, why? There is no valid reason for this.
Post by Ron Natalie
Post by Falk Tannhäuser
Post by Marcos Boyington
So, in C++, the only way to prevent typecasting to a base class is by having
private inheritance (correct?).
Well, it doesn't totally prevent it, but just renders it private
(or protected, in case of protected inheritence).
It twarts implicit conversion, but a C-style cast can still force
a conversion to even an inaccessible base class. It's the one
thing that a C-style cast will do that there is no C++ style cast
equivelent.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Allan W
2005-01-04 18:51:00 UTC
Permalink
Post by Marcutio B
#4) "Use a function called to_Something"
I probably should've mentioned that I had already considered this,
however, although this is a valid solution, it's not the prettiest (implicit
conversions are not only convenient, they help prevent errors)
You can do the same thing with operator AbstractionLayer(), and
then you get your implicit casts.
Post by Marcutio B
Of course you can work around this by having composition or "using" - I.E.
either have a member object instead of inheriting (and having calls which
reroute the functionality), or inherit privately and then do "using" on all
the functions to make them public again. But why? Anything can be "worked
around", including making C an OOP-like language. But C++ is
supposed to
Post by Marcutio B
make things "easy". This is a valid usecase which is used often, and C++
allows us to override all other operators, except "convert to base class" -
again, why? There is no valid reason for this.
In the specific case of casting to an abstract base, surely there are
some
finite number of operations that the base declares, and I would suspect
that changes to this interface are relatively rare. Do you really find
redeclaring them with "using" that draconian?


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Marcutio B
2005-01-08 22:47:54 UTC
Permalink
I sent this a couple of days ago, but it's not showing up, so resending...
sorry if it's a duplicate.

Anyway, thanks Allan for the input. Unfortunately, you CAN'T do operator
AbstractionLayer(), that's what started this entire discussion :) It's not
allowed by C++, visual studio gives a horrible warning, but gcc gives a much
better one:

warning: conversion to a reference to a base class will never use a type
conversion operator



"using" is not that horrible. Although, you have to admit, it'd be much
nicer if it didnt' have to be done this way - if you're going to inherit
from a class privately simply so that typecasting to the base class is not
possible externally, and then make all the functions, or a majority of them,
public, why not simply have the ability to make the cast to base class
operator private instead?



However, in Example #2:

class FunctionalityLayer1 : protectected AbstractionLayer
{};
class FunctionalityLayer2 : protectected AbstractionLayer
{};
template <typename _FuncLayer>
class TypesafeLayer : private _FuncLayer
{
private:
operator _FuncLayer& () { return *this; }
};


It cannot be used. Take for example 2 kinds of lists: a static size list
and a dynamic size list. The static size list throws an exception when you
try to add a node and it's full. The dynamic list simply allocates more
memory. The FunctionalityLayer for the static sized list would obviously
have a function "set_size", which allows you to set the size of the list.
The dynamic list would of course have no need for such a function. You
can't put "using set_size;" in TypesafeLayer, because it will report an
error when you inherit from the dynamic list functionality layer.
Post by Marcutio B
Post by Marcutio B
#4) "Use a function called to_Something"
I probably should've mentioned that I had already considered
this,
Post by Marcutio B
however, although this is a valid solution, it's not the prettiest
(implicit
Post by Marcutio B
conversions are not only convenient, they help prevent errors)
You can do the same thing with operator AbstractionLayer(), and
then you get your implicit casts.
Post by Marcutio B
Of course you can work around this by having composition or "using" -
I.E.
Post by Marcutio B
either have a member object instead of inheriting (and having calls
which
Post by Marcutio B
reroute the functionality), or inherit privately and then do "using"
on all
Post by Marcutio B
the functions to make them public again. But why? Anything can be
"worked
Post by Marcutio B
around", including making C an OOP-like language. But C++ is
supposed to
Post by Marcutio B
make things "easy". This is a valid usecase which is used often, and
C++
Post by Marcutio B
allows us to override all other operators, except "convert to base
class" -
Post by Marcutio B
again, why? There is no valid reason for this.
In the specific case of casting to an abstract base, surely there are
some
finite number of operations that the base declares, and I would suspect
that changes to this interface are relatively rare. Do you really find
redeclaring them with "using" that draconian?
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Ron Natalie
2004-12-25 19:17:13 UTC
Permalink
Stew

By definition, this meat cannot be had altogether fresh,
but have the lifeless unfortunate available immediately after delivery,
or use high quality beef or pork roasts (it is cheaper and better to
cut up a whole roast than to buy stew meat).

1 stillbirth, de-boned and cubed
Œ cup vegetable oil
2 large onions
bell pepper
celery
garlic
œ cup red wine
3 Irish potatoes
2 large carrots

This is a simple classic stew that makes natural gravy,
thus it does not have to be thickened.
Brown the meat quickly in very hot oil, remove and set aside.
Brown the onions, celery, pepper and garlic.
De-glaze with wine, return meat to the pan and season well.
Stew on low fire adding small amounts of water and
seasoning as necessary.
After at least half an hour, add the carrots and potatoes,
and simmer till root vegetables break with a fork.
Cook a fresh pot of long grained white rice.



Pre-mie Pot Pie

When working with prematurely delivered newborns (or chicken) use sherry;
red wine with beef (buy steak or roast, do not pre-boil).

Pie crust (see index)
Whole fresh pre-mie; eviscerated, head, hands and feet removed
Onions, bell pepper, celery
œ cup wine
Root vegetables of choice (turnips, carrots, potatoes, etc) cubed

Make a crust from scratch - or go shamefully to the frozen food section
of your favorite grocery and select 2 high quality pie crusts (you
will need one for the top also).
Boil the prepared delicacy until the meat starts to come off the bones.
Remove, de-bone and cube; continue to reduce the broth.
Brown the onions, peppers and celery.
Add the meat then season, continue browning.
De-glaze with sherry, add the
Ron Natalie
2004-12-25 23:12:48 UTC
Permalink
gravy,
enough to make the mixture pliable.
Divide the stuffing among the cabbage leaves then roll.
Place seam down in a baking pan.
Ladle tomato gravy on top,
and bake at 325° for 30 - 45 minutes.



Umbilical Cordon Bleu

Nothing is so beautiful as the bond between mother and child,
so why not consume it?
Children or chicken breasts will work wonderfully also.

4 whole umbilical chords (or baby breasts, or chicken breasts)
4 thin slices of smoked ham, and Gruyere cheese
Flour
eggwash (milk and eggs)
seasoned bread crumbs
1 onion
minced
salt
pepper
butter
olive oil

Pound the breasts flat (parboil first if using umbilical
cords so they won?t be tough).
Place a slice of ham and cheese on each, along with some minced onion
then fold in half, trimming neatly.
Dredge in flour, eggwash, then seasoned breadcrumbs;
allow to sit for a few minutes.
Sauté in butter and olive oil until golden brown,
about 6 minutes on each side.



Shish Kababes

As old as the hills, this technique has employed seafood, beef, pork, lamb,
poultry, and v
Jonathan Mcdougall
2004-12-23 11:56:33 UTC
Permalink
Post by Marcos Boyington
Hey guys, quick question about how C++ designers chose to not implement
this, I'm sure there are some people here who can take a better guess at it
than I.
So, in C++, the only way to prevent typecasting to a base class is by having
private
and protected
Post by Marcos Boyington
inheritance (correct?). However, this prevents one from doing 2
Example #1: Allow conversion from child -> grandparent, but NOT child ->
parent.
class AbstractionLayer
{};
class FunctionalityLayer : protectected AbstractionLayer
{};
template <typename _T>
class TypesafeLayer : private FunctionalityLayer
{};
We want to be able to cast to AbstractionLayer, but not to
FunctionalityLayer (this is an internal class which has funcitonality, but
we don't want usage of this class directly). However, we do want to
typecast to an AbstractionLayer.
template <class T>
class TypesafeLayer : public AbstractionLayer,
private FunctionalityLayer
{
};
Post by Marcos Boyington
Example #2: Limit typecasting but allow function usage
Say we have something similar to the above, i.e. a class with functionality.
We want these functions to be externally accessible to others, HOWEVER, we
do NOT want it to be typecasted to the base class. Sure we can do "using"
for all the functions, but this becomes a hassle if we add functionality, as
we have to modify both classes.
Either A is a B or A is not a B. You cannot have both so you're stuck
with using declarations or function forwarding. Your design seems to be
flawed somehow.
Post by Marcos Boyington
Lastly, in a case such as this, we are left
class FunctionalityLayer1 : protectected AbstractionLayer
{};
class FunctionalityLayer2 : protectected AbstractionLayer
{};
template <typename _FuncLayer>
class TypesafeLayer : private _FuncLayer
{};
That's too bad, and that's another indication that your design is
impraticable.
Post by Marcos Boyington
Anyone know if they're planning to add support to overriding the "conversion
to a reference to a base class operator", or why it hasn't been done yet?
The above examples are shown below with this operator, if C++ were to
class AbstractionLayer
{};
class FunctionalityLayer : protectected AbstractionLayer
{};
template <typename _T>
class TypesafeLayer : private FunctionalityLayer
{
operator AbstractionLayer& () { return *this; }
};
class FunctionalityLayer1 : protectected AbstractionLayer
{};
class FunctionalityLayer2 : protectected AbstractionLayer
{};
template <typename _FuncLayer>
class TypesafeLayer : private _FuncLayer
{
operator _FuncLayer& () { return *this; }
};
These should be illegal: TypesafeLayer is neither a FunctionalityLayer
nor a _FuncLayer, it is implemented in terms of these. It is a *good*
thing such construct is disallowed.

The whole thing seems to be caused my a misunderstanding/misuse of
public inheritance.


Jonathan

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
k***@gabi-soft.fr
2004-12-23 15:26:04 UTC
Permalink
Post by Marcos Boyington
So, in C++, the only way to prevent typecasting to a base class is by
having private inheritance (correct?). However, this prevents one
Example #1: Allow conversion from child -> grandparent, but NOT child
-> parent.
class AbstractionLayer
{};
class FunctionalityLayer : protectected AbstractionLayer
{};
template <typename _T>
class TypesafeLayer : private FunctionalityLayer
{};
We want to be able to cast to AbstractionLayer, but not to
FunctionalityLayer (this is an internal class which has
funcitonality,
Post by Marcos Boyington
but we don't want usage of this class directly). However, we do want
to typecast to an AbstractionLayer.
The usual way to do this is via virtual inheritance:

class AbstractionLayer {} ;

class FunctionalityLayer : public virtual AbstractionLayer {} ;

class TypesafeLayer
: public virtual AbstractionLayer
, private FunctionalityLayer {} ;

The idea here is that TypesafeLayer isA AbstractionLayer, and that the
inheritance from FunctionalityLayer is just an implementation detail.
(See Barton and Nackman, for example.)

In practice, I think that most people just don't worry about it. As
far as users are concerned, no one is really interested in casting to
FunctionalityLayer anyway, so the feared missuse just doesn't occur in
practice.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Continue reading on narkive:
Loading...