Topic: inheritance and return type
Author: kohtala@hardy.trs.ntc.nokia.com (Kohtala Marko)
Date: 12 Sep 1994 16:54:59 GMT Raw View
In article <CALVITTI.94Sep7121913@cthulhu.ces.cwru.edu> calvitti@cthulhu.ces.cwru.edu (Alan Calvitti) writes:
> In article <34innb$hk9@jac.zko.dec.com>
> jjf@falcon.unx.dec.com (John J. Franey) writes:
> > I've read and re-read the keyword argument passage in the book (S 6.5.11
> > p 156,57) and have failed to see where Stroustrup imagined this kind of
> > "flexibility". Even I, a relative novice, can see that your application
...
> I should have been clearer in explaining my example. I employ the
> keyword argument workaround in the following way: as illustrated in
> Stroustrup's book, an (unnamed) WinAttr object is passed as the only
> argument to the Window constructor, and window attributes, such as
> dimensions, name, etc., are set through WinAttr's member functions
> which return WinAttr& so that they can be chained together as in:
> Window w(WinAttr().dim(300,400).name("My Window"));
> This works perfectly well for Windows. But I derived a class from
> Window, and the workaround fumbles: concretely, the derived class,
> Canvas, is used to perform graphics output using an arbitratry
> coordinate system. It would be nice to specify the information
> specific to the Canvas class in the constructor as in:
>
> Canvas c(CanvAttr().dim(300,400).name("MyWindow").limits(-2,2,0,10));
> CanvAttr, inherited from WinAttr, provides the member function
> limits() (which only makes sense in a Canvas). Unfortunately, this
> does not compile, because the other members (dim, name, ....) return
> Window&, not Canvas&, and i have not defined the necessary copy
> constructor:
You need to redefine the derived member functions for the new return
type. Yes, it is a drag. Easier way out (on the user's expense) is to
require that the new attributes of the derived class (CanvAttr) be
specified first.
I do not have the latest ANSI C++ Working Paper which I hear has
nested templates. Would be interesting to know if this is going to
work:
class WinAttr
{
public:
WinAttr() {}
typedef WinAttr MyType;
template<class Return = MyType>
Return& param1(int value) { p1 = value;
return static_cast<Return&>(*this); }
//...
};
class CanvAttr : public WinAttr
{
public:
CanvAttr() {}
typedef CanvAttr MyType;
template<class Return = MyType>
Return& param2(int value) { p2 = value;
return static_cast<Return&>(*this); }
//...
};
It could be good (I can not tell if it would break something else), if
CanvAttr().param1(1).param2(2)
would be equal to
CanvAttr().param1<CanvAttr>(1).param2<CanvAttr>(2)
I do recognize there is a problem here that overloading can not be
done with the return value. I think it could easily pass if
CanvAttr().param1(1) instantiated a member function of CanvAttr even
if the template was inherited -- just have any second instantiation
for a class give an error for defining members that differ only in the
return type.
Another solution could be to have a class template which takes as a
parameter the class to return.
template<class Return>
class WinAttr
{
public:
WinAttr() {}
Return& param1(int value) { p1 = value;
return static_cast<Return&>(*this); }
//...
};
template<class Return>
class CanvAttr : public WinAttr<CanvAttr<Return> >
{
public:
CanvAttr() {}
Return& param2(int value) { p2 = value;
return static_cast<Return&>(*this); }
//...
};
Seems fine except that how do I define the template to return a
reference to it's own type. Naturally, it goes like this
WinAttr<WinAttr<WinAttr< /* When to stop? */ > > >
Any ideas how to do this in finite amount of typing?
One solution that I thought of, but can not tell if it would work, is:
template<class Return> class WinAttr;
template<class Return = WinAttr<Return> >
class WinAttr
{
//... as above
};
Whether this works will depend at least on the point of definition
(/declaration?) for the template parameter. Even if it worked, I'd
like to see the output of an error message printing the type
out.
Another one with similar problems:
typedef RealWinAttr; // Jan 94 WP says this declares the name as a type
typedef WinAttr<RealWinAttr> RealWinAttr; // Allowed?
Third one, where I find less questions about it's usability:
class RealWinAttr : public WinAttr<RealWinAttr> { };
class RealCanvAttr : public CanvAttr<RealCanvAttr> { };
This third one is actually accepted by gcc 2.6.0. It would be a very
good solution unless it loose things that are not inherited. Since the
inheritance is a bit problematic, would be good if the previous
solutions worked.
Someone should put these in some torture suit.
Have these been thought about in the ANSI C++ working group? I
crosspost this to comp.std.c++ to make sure.
--
---
Marko Kohtala - Marko.Kohtala@ntc.nokia.com, Marko.Kohtala@hut.fi
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Wed, 14 Sep 1994 08:24:33 GMT Raw View
In article <KOHTALA.94Sep12195459@hardy.trs.ntc.nokia.com> Marko.Kohtala@ntc.nokia.com writes:
>...
>This third one is actually accepted by gcc 2.6.0. It would be a very
>good solution unless it loose things that are not inherited. Since the
>inheritance is a bit problematic, would be good if the previous
>solutions worked.
>
>Someone should put these in some torture suit.
Hummmm... What exactly do you mean by `torture suit'? Is that sort of like
the equivalent of a `hair shirt' made especially for implementors?? :-)
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -