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 -