Duplicate inherited class

Hi!

I often get to this problem, so I'm asking here if anyone has a nice, sexy and OO way to do it.

I've got a base class A and two classes B and C inherited from A.
I want to be able to duplicate the classes independently if they are of type B or C.

What I've got is something like that:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class A
{
public:
  A * duplicate() const = 0;

  int m_dataFromA;
};

class B : public A
{
public:
  A * duplicate() const
  {
    B * b = new B;
    b->m_dataFromA = m_dataFromA;
    b->m_dataFromB = m_dataFromB;
    return b;
  }

  int m_dataFromB;
};

class C : public A
{
public:
  A * duplicate() const
  {
    C * c = new C;
    c->m_dataFromA = m_dataFromA;
    c->m_dataFromC = m_dataFromC;
    return c;
  }

  int m_dataFromC;
};
um, what's wrong with virtual? otherwise that's the solution (with virtual in front of duplicate).

you can also write in duplicate: (*c) = (*this) that would work as long as you don't have const members

B * b = new B;

C * c = new C;


Shouldn't the above two lines be something like this ?

1
2
3
A *b = new B;

A *c = new C;
oops, erratum, I forgot a virtual at the beginning of the duplicate declaration:
virtual A * duplicate() const = 0;

@coder777: the problem is that the duplicate() method must return a pointer to the class. This pointer have to be allocated by the final class (B or C) because it's the only one which knows its own type. That's why the duplicate() method from the class A can't be used to duplicate the data from A. I've changed my code, look at this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class A
{
public:
  A * duplicate() const = 0;

  void internalDuplicate(const A & _src)
  {
    m_dataFromA = A.m_dataFromA;
  }

  int m_dataFromA;
};

class B : public A
{
public:
  A * duplicate() const
  {
    B * b = new B;
    b->internalDuplicate(*this);
    b->m_dataFromB = m_dataFromB;
    return b;
  }

  int m_dataFromB;
};

class C : public A
{
public:
  A * duplicate() const
  {
    C * c = new C;
    c->internalDuplicate(*this);
    c->m_dataFromC = m_dataFromC;
    return c;
  }

  int m_dataFromC;
};


This way, I refactored the duplication of A.
If you look at it from a higher level, the duplicate function aims the leaf class directly. And once called it get its way back to its parents classes.
It's the nicer way I found of doing it, is there a better one?

@sohguanh: I don't think so (it works on Visual at least, I'll try this on gcc later). Because the function needs a pointer to A, and B (or C) is inherited from A, the implicit cast is done seamlessly.
well, the following
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class A
{
public:
  A * duplicate() const = 0;

  int m_dataFromA;
};

class B : public A
{
public:
  A * duplicate() const
  {
    B * b = new B;
    (*b) = (*this);
    return b;
  }

  int m_dataFromB;
};

class C : public A
{
public:
  A * duplicate() const
  {
    C * c = new C;
    (*c) = (*this);
    return c;
  }

  int m_dataFromC;
};
copies all the data (inlcuding the data from the base class A) to the newly created like c variable. This (*c) is the dereference operator of c.

Only if you don't want to copy all the data you should do it otherwise.
Ok, I see what you mean.
I'm not fond of overloading the operator = , when you have to deal with pointers, it can be a mess (but colors and opinions, you know... :)). But in the same idea, I could simply do a duplicate() and a copy() methods. duplicate() is in charge of allocating the returned pointer with the right type and it is virtual, and copy() will copy the data and can't be virtual. I think it's kinda nice.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class A
{
public:
  virtual A * duplicate() const = 0;

  void copy(const A & _src)
  {
    m_dataFromA = _src.m_dataFromA;
  }

  int m_dataFromA;
};

class B : public A
{
public:
  A * duplicate() const
  {
    B * b = new B;
    b->copy(*this);
    return b;
  }

  void copy(const B & _src)
  {
    A::copy(_src);
    m_dataFromB = _src.m_dataFromB;
  }

  int m_dataFromB;
};

class C : public A
{
public:
  A * duplicate() const
  {
    C * c = new C;
    c->copy(*this);
    return c;
  }

  void copy(const C & _src)
  {
    A::copy(_src);
    m_dataFromC = _src.m_dataFromC;
  }

  int m_dataFromC;
};


We can't virtualize the copy() method because its parameters needs to be of the right type. If you prefer it your way, you can simply replace copy() by operator = (), I think it'll work the same (but be careful with the pointers :))

Thanks!!
you don't need to overload the 'operator =' because each C++ class has it already (invisibly) that simply copies everything. You only need to overload it when you want to do something special.

Doing it with a copy method bears the danger of forgetting something.
Here is a link to the article on the clone pattern, which is what OP wants:
http://www.cplusplus.com/forum/articles/18757/
Well, I just put an "int" here for the data, but in my classes the data are special.
Thanks for the link jsmith. It's also named the Protoype pattern:
http://en.wikipedia.org/wiki/Prototype_pattern

Learned something else today :)
Topic archived. No new replies allowed.