0

This is a recurrent problem once again. Someone know a easy way to do that? Imagine I have the following:

class Base
{
    public:
        ...
        Base property(const std::string& name)=0;
};
class Derived:public Base
{
    public:
        Derived();
        Derived(const Derived&& val);
        Base property(const std::string& name)
        {
            Derived z;
            return z;
        }
 }

There is a way for the Derived::property return being (internally) a Derived copy instead of only Base part copy, and with the Derived move constructor invoked?

May be a stupid question, but really I dont find solution. Why copy constructors on return dont copy the specialized class?

Thanks you!

  • 1
    by passing by copy you can't return a object to derived type, and what if you use a prototype like : void property(const std::sring& name, Base& toFill) { Derived z; toFill = z; } – X3liF Jun 11 '15 at 08:44
  • 1
    Polymorphism is one of the few reasons to use pointers in C++ these days. And move constructors won't help here, read about [object slicing](http://stackoverflow.com/questions/274626/what-is-object-slicing). – Some programmer dude Jun 11 '15 at 08:46
  • But is very unpleasant. Stylistic speaking, breaks smart code. – Mel Viso Martinez Jun 11 '15 at 08:47

2 Answers2

3

You can't do this.

Returning by value conceptually (ignoring RVO and move semantics) means making a copy of whatever you return by using the copy constructor of the type which the function is declared to return. If you return a Derived, a copy of type Base will be made and you'll lose the Derived part of the object. This is known as slicing.

If you want to return a Derived object as a Base, you'll need to use pointers.

TartanLlama
  • 63,752
  • 13
  • 157
  • 193
  • I agree and known that. I see that as realy a bad design from C++ semantics that breaks dynamic code and enforce the use of pointers... – Mel Viso Martinez Jun 11 '15 at 08:50
  • Yes,... sniff. I like to represent in code the reality as near as I can. I hate to do encapsulation for this language flawors. I will relay in macros (I only use it when I'm very angry). – Mel Viso Martinez Jun 11 '15 at 08:55
  • 1
    This does represent the reality: if you have an object of type `Base`, it's a `Base`, not a `Derived` or a `Chicken`. Imagine the compiler had to do virtual function dispatch every time you called a function on your `Base` object. – TartanLlama Jun 11 '15 at 09:01
  • 1
    Be careful when using `std::unique_ptr` though, pass it by value to a function and you loose the ownership of the pointer. – Some programmer dude Jun 11 '15 at 09:01
  • I agree to desagree, @TartanLlama, you can declare Base& argument in method and pass Derived. The same sense may be applicable to return types : a return Derived holds allways a Base class. And yes, if you have a virtual method in base class, the vtable (although is implementation dependent) gets checked every time if you don't specify the exact class version to call. – Mel Viso Martinez Jun 11 '15 at 09:07
0

The only aproximation I can find for who search something similar (related with X3liF, TartanLlama and other responses)

#define overridable(T) ovr<T>
#define return_overload_allowed(TYPE) friend struct ovr<TYPE>; virtual void* clone() const
#define return_overload_basic_allowed(TYPE) friend struct ovr<TYPE>; virtual void* clone() const{return new TYPE(*this);}

template<typename T> struct ovr
{
 T* _obj;
 ovr(const T& t)
 : _obj(reinterpret_cast<T*>(t.clone()))
 {;}
 ovr(ovr<T>&& v)
    : _obj(v._obj)
    {
     v._obj=nullptr;
    }
 operator T&()
 {
  return *_obj;
 }
 virtual ~ovr()
 {
  delete _obj;
 }
};


class BASE
{
 return_overload_basic_allowed(BASE);
public:
 virtual overridable(BASE) method1();
 virtual ~BASE();
};

class DERIVED: public BASE
{
 return_overload_basic_allowed(DERIVED);
public:
 virtual overridable(BASE) method1()
 {
  DERIVED a;
  return a;
 }
 virtual ~DERIVED();
 
};

DERIVED a;
auto x = a.method1();
BASE& really_derived = x;

This compiles fine. But don't meet practical and smart requiriments... :(