Diseño de clase / jerarquía C ++

I heave roughly speaking the following hierarchy

class Base {
public:
    virtual int value() const = 0;
};

class Derived1 : public Base {
public:
    int value() const {
        return 1;
    }
};

class Derived2 : public Base {
public:
    int value() const {
        return -1;
    }
};

class Derived3 : public Base {
public:
    Derived3(const Base & underlying);
    int value() const {
        return underlying_.value() + 10;
    }
private:
    const Base & underlying_;
};

Derived3::Derived3(const Base & underlying)
:underlying_(underlying) {}

There is also a singleton holder for Base objects. One branch of the workflow goes something like this:
1) Get a Derived1 object out of the holder
2) Instantiate a Derived3 object using the Derived1 object and use it.

I'm in a multithreaded environment and am worried about the problem of the underlying_ reference_ becoming invalidated during the lifetime of the second object. I am not an expert on multithreading but I believe this can happen.

I would like for Derived2 objects to own a copy of the underlying object but because Base is abstract I cant do that. Can someone comment of this design and suggest a different approach.

To add, there are two driving thoughts behind the above design. Derived3 should be though of as a shift of Base type objects. One desire is to have shifts of shifts. Another desire is to be able to store Derived3 objects in the singleton for possible use later.

preguntado el 08 de noviembre de 11 a las 13:11

Is it intentional that Derived3 is derived from Base but also as a reference to a Base? Also, you have Derived3::Derived2, when I think you meant Derived3::Derived3. -

The code you provided is not related to multithreading. The problems are inside the "holder" logic (you didn't provide) and the meaning of 2) (doesn't have any construction based on Derivd1... so ... ) -

Fixed typos and explained some design thought in the edit. Sorry Emilio, 2) should read "Instantiate Derived 3 ...". -

2 Respuestas

You can try to 'clone' your classes. I mean, each derived class may clone itself and use this clone in others derived.

class Base {
    public:
        virtual Base *clone() const = 0;
};

class Derived2 : public Base {
    public:
        int value() const {
           return -1;
        }
        Derived2(const Derived2 &)
        {
            ....
        }
        Base *clone() const
        {
            return new Derived2(*this);
        }
};

With this solution, you can hold new Derived all time you need. Don't forget to delete it. Your factory returns a Base object that can be cloned to obtain a new one.

respondido 08 nov., 11:18

I think this maybe what I need. Let me give this a try. Thank you - stas

Be sure to make your Base destructor be virtual. - Vaughn Cato

Yeah, I know that much at least. Thank you - stas

Cloning is a common approach to making a copy when you just have a pointer or reference to an abstract class.

struct A {
  virtual A* clone() const = 0;
  virtual ~A() { }
};

struct B : A {
  virtual A* clone() const { return new B(*this); }
};

struct C {
  A* ap;

  C(A* ap_arg) : ap(ap_arg->clone()) { }
  ~C() { delete ap; }
};

respondido 08 nov., 11:18

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.