简体   繁体   中英

Usefulness of covariant return types in C++ clone idiom?

The usual clone idiom makes use of covariant return types:

struct Base {
    virtual Base* clone();
};

struct Derived : public Base {
    Derived* clone();
};

I've read things to the effect that covariant return types were a later addition to C++, and older compilers may not support them. In this case the Derived class must declare its clone member function to return a Base* . Since, presumably, I'm only accessing Derived objects through Base pointers and/or references when using this idiom, what is the real use/benefit to declaring the return type Derived* ?

Also, a related question:

I would prefer to use smart pointers to express transfer-of-ownership semantics for the clone signature. This is not possible when using covariant return types, as auto_ptr<Derived> is not covariant with auto_ptr<Base> . (Please note that I'm not looking for a lecture on the use of smart pointers -- auto_ptr is just used as an example here). So in this case, is there any reason not to have Derived return auto_ptr<Base> ? Is there a better way to express the transfer-of-ownership semantics?

Since, presumably, I'm only accessing Derived objects through Base pointers and/or references when using this idiom...

You presume wrong. Just because a Base class exists doesn't mean you'll always be using it. If I have a Shape class with sub classes Circle and Rectangle , and I also have a Window class. I'm not going to use a Shape* for a the window's position and size when I can just use Rectangle .

For the transfer-of-ownership, you shouldn't be using smart pointers anyway. I know you don't want a lecture, but I'm not saying that smart pointers are bad, you just shouldn't be using them in clone() . You can't transfer ownership of something that has no ownership in the first place. If someone wants an auto_ptr then they should construct it with the cloned raw pointer. Same goes for other smart pointer types.

It's useful when you have a pointer to Derived and want to get a clone of it:

Derived *ptr = ...;
Derived *clone = ptr->clone();

without covariant return types you must do an explicit cast:

Derived *clone2 = (Derived*)ptr->clone();

Note that Derived may be a base class for even more derived classes, in that case it makes even more sense.

Unfortunately auto_ptr<Derived> and auto_ptr<Base> are not covariant. So you must return the same type from all clone functions in that case.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM