开发者

How can I assign a child class to a base class?

开发者 https://www.devze.com 2023-01-16 20:59 出处:网络
I know there are solved questions related to this issue, but I still can\'t figure out how to resolve my problem.

I know there are solved questions related to this issue, but I still can't figure out how to resolve my problem.

I have something like this:

class Base
{
   static Base* createBase()
   {
      Base *b = new Base();
      ... //does a lot of weird things
      return b;
   }
}

class Child : public Base
{
   static Child* createChild()
   {
      Child *c = createBase(); // error
      return c;          
   }
}

I know why it doesn't work, but I have to find a way to do it. The createBase funct开发者_运维百科ion does a lot of things so I don't want to recode it.

Any suggestions?


Why do you expect that to work? You can't treat a Base object as if it were a Child object, because the Child class might have all sorts of additional data that Base does not.

In order to get the effect you're looking for, there are two ways to do it:

The first way, and probably the best idea, is to move the logic from createBase into the Base constructor. The Base constructor will run whether you're creating a Base or something derived from it. It looks like you're trying to do the work of initializing the base object, and that's exactly what constructors are for!

If for some reason this will not work in your case, the other option is to create a protected initialize method in Base which accepts a Base* and does all the work that you are currently doing in createBase, e.g.

class Base
{
  public:

   static Base* createBase()
   {
       Base* b = new Base();
       initialize(b);
       return b;
   }

  protected:

   static void initialize(Base* b)
   {
      ... //does a lot of weird things
   }
}

class Child : public Base
{
  public:
   static Child* createChild()
   {
      Child *c = new Child(); 
      initialize(c):
      return c;          
   }
}

Note that this works since, while you can't treat a Base* as if it were a Child*, you can go the other way and treat a Child* as if it were a Base*, because the Child class is guaranteed to have at least everything that the Base class does, due to the nature of inheritance.

Edit: I saw you post in a comment to another answer that you cannot modify the definition of Base. In that case, you are completely out of luck and you will have to accept the need to copy-and-paste, given the restrictions in play. You are not going to be able to call createBase and get back a pointer to an object of any type other than Base if you cannot modify its code.


overloading new for Base class might solve your issue.

class UTIL{

static size_t size;

public: static void setSize(size_t t) { //mutex protection size = t; }

static size_t getsize(); // should only be called from inside new of class A

};

class A { int i;

public: static A* createA() {

    A* a = new A();
    a->i = 10;
    return a;
}

void* operator new (size_t size) throw (const char *){

void * p = malloc(UTIL::getsize());

if (p == 0) throw "allocation failure";

return p;

}

void operator delete (void *p){

free(p); }

};

size_t UTIL::size = sizeof(A);

size_t UTIL::getsize() {

    //mutex protection
    size_t tmp = size;
    size = sizeof(A);
    return tmp;

}

class B {

public: int j; static B* createB() {

           //take mutex

    UTIL::setSize(sizeof(B));
    B* b = (B*)(A::createA());
    b->j = 20;
    //release Mutex
    return b;
}

};


Perhaps you should re-define createBase as follows:

template< class TheClass > static TheClass* create()
{
  TheClass *ret = new TheClass();
  ... //does a lot of weird things
  return ret;
}

You can then create an object as follows:

Child* pChild = create< Child >();

This may not be appropriate depending what the "weird" things are but its one possible way of solving your issues.


You should be using

Child *c = new Child();

Otherwise you are trying to create a Base class instance and call it a Child.

RE your comment:

Perhaps you could change

static Base* createBase();

static void createBase(Base *b);

If you pass the instance into this method you could use it with both Child and Base

for example:

Base *b = new Base();
Base::createBase(b);

Child *c = new Child();
Base::createBase(c);

or alternatively

static Base *createBase(Base *b = NULL){
    if(b == NULL){
        b = new Base;
    }
    //do your stuff
    return b;

and for the child:

static Child* createChild(){
    Child *c = new Child;
    createBase(c);
    return c;

This way you can use both:

b = Base::createBase();
c = Child::createChild();


Don't the "weird" things belong in the Base constructor. Then by constructing the Child your base gets properly constructed?

Otherwise just refactor the code into a method you call from both places - definately don't copy it.


You can use constructors to do the work for you:

class Base
{
   Base()
   {
     // does a lot of weird things
   }

  static Base* createBase()
  {
     return new Base();
  }

};

class Child : public Base
{
   Child()
   {
      // Do child's weird things here        
   }

  static Child* createChild()
  {
     return new Child();
  }
};

Base *instance1 = new Child();  // Works as expected
Base *instance2 = Child::createChild();  // Works as expected
Base *instance3 = new Base();  // Works as expected
Base *instance4 = Base::createBase();  // Works as expected

EDIT:
If you can't modify the Base class, you shouldn't derive from it this way. The class is apparently meant to have its own functionality and the static construction method suggests some more complex usage. You might want to use the Decorator design pattern instead of inheritance in this case: http://en.wikipedia.org/wiki/Decorator_pattern


how about this

class Base
{
public:
   static Base* createBase()
   {
      Base *b = new Base();
      //does a lot of weird things
      return b;
   }
};

class Child
{
   protected:
   Base* m_basePtr;

public:
   operator Base&(){return *m_basePtr;}
   static Child* createChild()
   {
      Child *c=new Child;
      c->m_basePtr=Base::createBase();
      return c;          
   }
};

but you have to delete the pointer at the destructor


What you want to do is:

class Base
{
  Base()
  {
         ... //does a lot of weird things
  }
};

class Child : public Base
{
  Child Child() // This calls the base constructor auto-magically
  {
  }
}

int main()
{
    Child  childOne;
    Base   baseOne;

    Child*  childPtr = new Child();
    Base*   basePtr1 = new Child();
    Base*   basePtr2 = new Base();
}
0

精彩评论

暂无评论...
验证码 换一张
取 消