Link to home
Start Free TrialLog in
Avatar of DJ_AM_Juicebox
DJ_AM_Juicebox

asked on

Copying a virtual baseclass

Hi,

I have something like this:

    vector<BaseType*>  Stuff;
    Stuff.push_back(new DerivedType());

Later in my app, I want to make a copy of that object. What's the right way to do it?

    BaseType* pCopy = new BaseType(Stuff[0]);

I'm not quite sure what will happen because Stuff[0] is now represented as a base type even though it was allocated as a derived type. I want to allocate a copy of it as a base type to interact with it via it's base class interface.

Thanks
Avatar of Jaime Olivares
Jaime Olivares
Flag of Peru image

BaseType* pCopy = new BaseType(Stuff[0]);

if you want a copy, this is good approach, as far the Base's copy constructor is well implemented as:

BaseType::BaseType(BaseType &old)
Avatar of evilrix
Of course, if the base class is an abstract class this won't work!
This won't work...
#include <vector>
 
struct A
{
	virtual void foo() = 0;
};
 
struct B : A
{
	void foo(){}
};
 
int main()
{
	std::vector<A *> v;
 
	v.push_back(new B);
	A const *a2 = new A(*v[0]);
 
	a2.foo();
}

Open in new window

I think you need to ask yourself why you want to do this! It is not a particularly safe thing to do as you'll be 'slicing' the type if it was originally created from a derived class. Maybe it would be better if you stated here why you think you need to do this as there is probably a better way!
You can have a virtual copy method - something like this :

#include <iostream>
 
class Base {
  protected :
    int val;
  public :
    Base(int v) : val(v) { }
    Base(Base &b) : val(b.val) { }
    virtual Base *copy() {
        return new Base(*this);
    }
    virtual void print() {
        std::cout << "Base (" << val << ") !!" << std::endl;
    }
};
 
class Derived : public Base {
  public :
    Derived(int v) : Base(v) { }
    Derived(Derived &d) : Base(d.val) { }
    virtual Derived *copy() {
        return new Derived(*this);
    }
    virtual void print() {
        std::cout << "Derived (" << val << ") !!" << std::endl;
    }
};
 
int main(void) {
  Base b(5);
  Derived d(10);
  
  Base *bp = &b;
  bp->print();
  Base *bp2 = bp->copy();
  bp2->print();
  delete bp2;
  
  bp = &d;
  bp->print();
  bp2 = bp->copy();
  bp2->print();
  delete bp2;
  
  return 0;
}

Open in new window

But it's not very pretty ... so you need a good reason ;)
>> so you need a good reason
Yes indeed -- It's potentially unsafe if you don't realize you've sliced and still expect polymorphic behavior!
Providing a constructor and assignment operator in the sub class for the super class is probably the best and safest way to do this...
#include <vector>
 
class A
{
public:
	A(int x): m_x(x){}
	virtual void foo() = 0;
 
	void set_x(int x) { m_x = x; }
	int get_x() const { return m_x; }
 
private:
	int m_x;
};
 
class B : public A
{
public:
	B():A(0){}
 
	// Constructor to construct from A
	B(A const & a): A(a), m_y(0){}
 
	// Assignment operator to assign A
	B & operator=(A const & a)
	{
		if(this != &a)
		{
			A::set_x(a.get_x());
			m_y = 0;
		}
 
		return *this;
	}
 
	void foo(){}
 
private:
	int m_y;
};
 
int main()
{
	std::vector<A *> v;
 
	v.push_back(new B);
	A const *a2 = new B(*v[0]);
}

Open in new window

>>         A const *a2 = new B(*v[0]);

But that means you have to know the type - ie. it's not polymorphic.
Unless you have access to modify the base class to force polymorphic copy via a virtualized method (as you have demonstrated) there is no other way to do this.
NB. The question never stated is had to be polymorphic!
>>Later in my app, I want to make a copy of that object. What's the right way to do it?
>> NB. The question never stated is had to be polymorphic!

It just seemed logical ;)
I'm not saying your solution isn't right, but it assumes

a) You have access to modify the base
b) The solution has to be polymorphic

:-p
Also, try putting a pure and virtual function in the base, your copy version will fail!
Avatar of DJ_AM_Juicebox
DJ_AM_Juicebox

ASKER

Hmm ok here's why I (think) I need to do it:

class BaseType {
      virtual bool IsMyType(string str) = 0;
      virtual bool ExecuteStuff() = 0;
};

class Apple()
{
      int m_MemberVar;
      bool IsMyType() { return str == "Apple"; }
      bool ExecuteStuff()
      {
          m_MemberVar = 55;
           return true;
      }
};

int main()
{
    vector<BaseType*> Stuff;
    Stuff.push_back(new Apple);
    Stuff.push_back(new Orange);

     RunThread(&Stuff);
     RunThread(&Stuff);
}

void RunThread(vector<BaseType*>)
{
      for (all in vector) {
            if (it->IsMyType()) {
                 it->ExecuteStuff();
            }
     }
}  

I hope the pseudo code is somewhat clear. Each thread can use that vector to check if some data matches one of the allocated types. If it does, I want to call their ExecuteStuff() function, but that will modify member variables, and if that's being done between threads I will get some unexpected results.

So at the moment if I realize that a type matches, I wanted to make a local copy for it to execute its function safely:

    if (it->IsMyType()) {
         BaseType* pTemp = new BaseType(it);
         pTemp->ExecuteStuff();
     }

I know it's kind of ugly, I hope what I'm trying to do makes sense in the sample!
Just a small side-note ... instead of copy, I should have named the method clone ... It's a nicer name :)
Why don't you just synchronize access to the vector using a Mutex?
>> Why don't you just synchronize access to the vector using a Mutex?

That would be easier indeed ...

And from your example, it seems you don't need polymorphic copies, since you know the type of the object the moment you want to copy it ... so, evilrix's approach would work nicely (no need for my virtual clone method) if you still want to copy.
This is how to implement a clone method so that it is (a) polymorphic and (b) will work event with an abstract base class: -
#include <vector>
 
class A
{
public:
	A(int x): m_x(x){}
	virtual void foo() = 0;
 
	void set_x(int x) { m_x = x; }
	int get_x() const { return m_x; }
 
	virtual A * clone() = 0;
 
private:
	int m_x;
};
 
class B : public A
{
public:
	B():A(0){}
 
	// Constructor to construct from A
	B(A const & a): A(a), m_y(0){}
 
	// Assignment operator to assign A
	B & operator=(A const & a)
	{
		if(this != &a)
		{
			A::set_x(a.get_x());
			m_y = 0;
		}
 
		return *this;
	}
 
	A * clone()
	{
		return new B(*this);
	}
 
	void foo(){}
 
private:
	int m_y;
};
 
int main()
{
	std::vector<A *> v;
 
	v.push_back(new B);
	A const *a2 = v[0]->clone();
}

Open in new window

And another way that uses static polymorphism to ensure that the clone method on B can return a type B* rather than a type A* (just in case that was a problem)
#include <vector>
 
template <typename subT>
class AT
{
public:
	AT(int x): m_x(x){}
	virtual void foo() = 0;
 
	void set_x(int x) { m_x = x; }
	int get_x() const { return m_x; }
 
	virtual subT * clone() = 0;
 
private:
	int m_x;
};
 
class B;
typedef AT<B> A;
 
class B : public A
{
public:
	B():A(0){}
 
	// Constructor to construct from A
	B(A const & a): A(a), m_y(0){}
 
	// Assignment operator to assign A
	B & operator=(A const & a)
	{
		if(this != &a)
		{
			A::set_x(a.get_x());
			m_y = 0;
		}
 
		return *this;
	}
 
	B * clone()
	{
		return new B(*this);
	}
 
	void foo(){}
 
private:
	int m_y;
};
 
int main()
{
	std::vector<A *> v;
 
	v.push_back(new B);
	A const *a1 = v[0]->clone();
}

Open in new window

However, I think the solution to your problem is probably to use this....

http://msdn2.microsoft.com/en-us/library/ms682411.aspx
ASKER CERTIFIED SOLUTION
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
gahhhh my head is gonna explode.

Ok let me review this,

Thanks
Ok guys I just read through.

I want the solution to be polymorphic, and I do have access to the base class (which is indeed abstract).

So I guess I can go with Infinity's solution (6th post down?). I don't want to use a critical section because I think it's too much compared to simply copying the object. There may be hundreds of threads simultaneously wanting to use it and I'm afraid even the CS would slow things up.

Thanks
>> which is indeed abstract
>> So I guess I can go with Infinity's solution (6th post down?).
I've already pointed out it won't work for abstract -- see the modified version I posted that will!
>> I don't want to use a critical section because I think it's too much compared to simply copying the object.
You're joking right? Using the critical section has far less over head and is simple -- the overhead of a heap allocation and copy is far greater

>> There may be hundreds of threads simultaneously wanting to use it and I'm afraid even the CS would slow things up
I guarantee a copy each time a thread needs access will be a far more costly exercise. As long as the time to execute is minimal the contention of the critical section should be negligible compared to continuous heap allocations. Heap allocations are very costly performance wise; especially if you plan of doing lots of them continuously! Another problem you have with lots of heap allocations is memory fragmentation. The more the memory fragments the slower it will become as the OS tries to find suitable free blocks in the free list..

I think possibly the problem here is that your original design may not really be suitable for what you are trying to do; however, in so far as your original question goes I believe it has now been thoroughly answered.
I strongly suggest you read these before you decide to dismiss Criitcal Section in favour of frequent small heap allocations: -

http://msdn2.microsoft.com/en-us/library/ms810466.aspx
http://support.microsoft.com/default.aspx?scid=kb;en-us;Q323635
Also, access to the heap is protected by a mutual exclusion locks  to prevent multi-threading issues -- so you'll still encounter exactly the same contention issues of using a Critical Section but with the added overhead of the extra work involved in heap allocations!
Ok I see your points. I guess my only (somewhat) valid concern is from an end user's point of view. I just happen to be desgning the class to work in a multithreaded environment, but it could just as well be used in a single threaded environment - in which case they may be really confused as to why I injected a critical section into the class (without having marked for use most likely in a MT environment). I guess it is just not working the way I expected when I first started because I'm trying to desgn the class to do be safe in any situation.

Thanks for all your answers!
Well, is the class is designed to work in an MT application either it needs to protect itself or you need to protect it then you use it. Protecting itself provides good encapsulation. You can always conditionally compile in or out the critical section code to provide ST or MT semantics but that'll probably just make the code more confusing :).
>> >> which is indeed abstract
>> >> So I guess I can go with Infinity's solution (6th post down?).
>> I've already pointed out it won't work for abstract -- see the modified version I posted that will!

To be fair : there was no mention of the base class being abstract when I posted ... What I posted was really just to give you an idea of how you could do it - you still had to adapt it to your specific situation of course.
Agreed, but it's kind of a moot point because copying the class wasn't the best way to solve this problem anyway :)