Path: utzoo!utgpu!news-server.csri.toronto.edu!mailrus!wuarchive!usc!sdd.hp.com!decwrl!uunet!microsoft!bobatk From: bobatk@microsoft.UUCP (Bob ATKINSON) Newsgroups: comp.std.c++ Subject: Re: the most dissatisfying part of c++ Message-ID: <56236@microsoft.UUCP> Date: 1 Aug 90 19:13:52 GMT References: <27634@netnews.upenn.edu> Reply-To: bobatk@microsoft.UUCP (Bob ATKINSON) Organization: Microsoft Corp., Redmond WA Lines: 138 Limsoon Wong writes: > >the program below is a contrived one. it cannot be compiled. >the reason is a type fault. however, it exhibits a very central >characteristic of update. something should be done to allow >this kinds of programs. ---limsoon. > > > >#include >class a { > public: > a& test() { > // do some modification to the state of this object, > // then ... > return *this; >}; >class b : public a { > public: > int b; >}; >main() { > b B; > B = B.test(); > // type violation despite the fact that > // `B' and `B.test()' are the same object. >} This is a not-infrequent idiom. Another example of its use is creating a "copy" method for collections (what's the return type?) What one would like to write is class Collection { public: virtual ??? Copy(); }; which will then be overridden in derived classes to do the appropriate copy operation. Replacing the question marks with "Collection*" is not acceptable, for then clients would loose static type information, as in class Collection { public: virtual Collection* Copy(); }; class Set : public Collection { public: virtual Collection* Copy(); // override for implementation } //... Set* pset, pset2 = ...; pset = pset2->Copy(); // illegal! An approach to solving this problem involves using _non-virtual_ member functions. class Collection { protected: virtual Collection* _Copy(); // The real copy function public: Collection* Copy() { return _Copy(); } }; class Set : public Collection { virtual Collection *_Copy(); // override implemenation public: Set* Copy() { return (Set *)_Copy(); } } //... Set* pset, pset2 = ...; pset = pset2->Copy(); // legal now In the context of the example Limsoon presented, we would write: class a { protected: virtual void _test() { /* do the real work here } public: a& test() { _test(); return *this; } }; class b : public a { public: b& test() { _test(); return *this; } }; main() { a A; b B; B = B.test(); // legal } Yes, this is tedious for the class writer, but it makes client's job a lot easier. I personally agree, though, that it would be worthwhile investigating making the following constructions legal: class Collection { public: virtual Collection * Copy(); }; class Set : public Collection { public: virtual Set * Copy(); // illegal today }; At present, this gives an illegal virtual return type error. The change to the existing rules is to allow overidings of virtual functions to return a type to which a standard conversion may be applied to obtain the inherited return type. ("standard conversion" may be too general; perhaps only derived-to-base standard conversions should be applicable). The appropriate member function signature would be chosen according to the static type of the pointer through which it is invoked. Bob Atkinson Microsoft [Disclaimer: I am but one solitary opinionated C++ programmer]