6

The following code tries to copy an object and keep the original type. Unfortunately it does not work (every copied object will become a Super instead of being of the same class as its original).

Please note that copySuper(const Super& givenSuper) should not know anything about the subclasses of Super.

Is it possible to do such a copy? Or do I have to change the definition of copySuper ?

#include <string>
#include <iostream>

class Super
{
public:
    Super() {};
    virtual ~Super() {};

    virtual std::string toString() const
    {
        return "I'm Super!";
    }
};

class Special : public Super
{
public:
    Special() {};
    virtual ~Special() {};

    virtual std::string toString() const
    {
        return "I'm Special!";
    }
};

Super* copySuper(const Super& givenSuper)
{
    Super* superCopy( new Super(givenSuper) );
    return superCopy;
}

int main()
{
    Special special;
    std::cout << special.toString() << std::endl;

    std::cout << "---" << std::endl;

    Super* specialCopy = copySuper(special);
    std::cout << specialCopy->toString() << std::endl;

    return 0;
}

//Desired Output:
// # I'm Special!
// # ---
// # I'm Special!
//
//Actual Output:
// # I'm Sepcial!
// # ---
// # I'm Super!
MOnsDaR
  • 8,401
  • 8
  • 49
  • 70

4 Answers4

13

Try this:

class Super
{
public:
    Super();// regular ctor
    Super(const Super& _rhs); // copy constructor
    virtual Super* clone() const {return(new Super(*this));};
}; // eo class Super


class Special : public Super
{
public:
    Special() : Super() {};
    Special(const Special& _rhs) : Super(_rhs){};
    virtual Special* clone() const {return(new Special(*this));};
}; // eo class Special

Note that we have implemented a clone() function that Special (and any other derivative of Super) overrides to create the correct copy.

e.g:

Super* s = new Super();
Super* s2 = s->clone(); // copy of s
Special* a = new Special();
Special* b = a->clone(); // copy of a

EDIT: As other commentator pointed out, *this, not this. That'll teach me to type quickly.

EDIT2: Another correction.

EDIT3: I really should not post so quickly when in the middle of work. Modified return-type of Special::clone() for covariant return-types.

Moo-Juice
  • 38,257
  • 10
  • 78
  • 128
  • Precisely what I was about to say...+1 – Jaywalker Nov 08 '10 at 10:07
  • @Moo: Also correct this line. Special* b = b->clone(); // copy of a It should be a->clone(); – bjskishore123 Nov 08 '10 at 10:20
  • one more thing. Your code will not compile, because of this line 'Super();/ regular ctor' – BЈовић Nov 08 '10 at 11:05
  • I can't take the blame for that one, I'm afraid. I swear the editor screws with me sometimes, as that was correct on posting. Anyway, thanks for pointing it out. – Moo-Juice Nov 08 '10 at 11:07
  • +1, though I would put the copy constructor and assignment operator as `protected` in every object because their unintentional use might lead to object slicing. I would also note that `return` being a keyword and not a function, there is a couple of extra parenthesis that we could do without. – Matthieu M. Nov 08 '10 at 17:05
  • @Moo-Juice: you could simplify the example by not using `new`, it's perfectly fine to instantiate the objects on the stack and I am afraid it may obscure more than help to have so many pointers. Also it would be better to use smart pointers for `s2` and `b` so as to show that even if the memory is returned by a dumb pointer (to exploit covariance) the caller is required to manage the memory and very strongly advised NOT to try to manage it manually (and fail). – Matthieu M. Nov 08 '10 at 17:10
4

This is what you need :

class Super
{
    public:
        Super()
        {
        }

        virtual Super* clone() const
        {
            return( new Super(*this) );
        };
};


class Special : public Super
{
    public:
        Special() : Super()
        {
        };
        Special(const Special& _rhs) : Super(_rhs)
        {
        };
        virtual Special* clone() const
        {
            return( new Special( *this ) );
        };
};

int main()
{
    Special a;
    Super &c( a );
    Super *b1 = c.clone();
    Special *b2 = a.clone();
    Super *b3 = a.clone();
}

One of previous examples has the clone for derived class wrong. The above is correct way of implementing the clone method.

BЈовић
  • 62,405
  • 41
  • 173
  • 273
3

What you want is generally implemented using an abstract clone method in the base class. Special will typically implement this method by returning new Special(*this).

Also note that it is considered a best practice to make base classes uncopyable.

icecrime
  • 74,451
  • 13
  • 99
  • 111
3

Just for the record, this is in the C++ FAQ:

http://www.dietmar-kuehl.de/mirror/c++-faq/abcs.html#faq-22.5

Georg P.
  • 2,785
  • 2
  • 27
  • 53
Stuart Golodetz
  • 20,238
  • 4
  • 51
  • 80