sgbrown
sgbrown

Reputation: 493

C++: Incorporating inheritance, polymorphism, and factories

I'm currently trying to make a pair of classes which depend on each other. Essentially, objects of class B create objects of class A. However, I am also using an inheritance hierarchy, so all derivatives of class B must also be able to create derivatives of class A (each derivative of B corresponds to a derivative of A, so DerB1 makes DerA1 objects, and DerB2 makes DerA2 objects).

I'm having problems with my implementation, and it may be silly, but I would like to see if anyone knows what to do. My code is below (I HATE reading other people's code, so I tried to make it as easy to read as possible...only a few important bits, which I commented to explain)

class BaseB {} // Declare BaseB early to use in BaseA constructor

class BaseA
{
public:
BaseA(BaseB* b) {}; // Declare the BaseA constructor (callable by all B classes, which pass a pointer to themselves to the constructor so the A objects can keep track of their parent)
}

class DerA:public BaseA
{
    DerA(BaseB* b):BaseA(b) {}; // Inherit the BaseA constructor, and use initialization list
}

class BaseB
{
public:
    virtual BaseA createA() = 0; // Virtual function, representing method to create A objects
}

class DerB:public BaseB
{
    BaseA createA() {
        DerA* a = new DerA(this); // Definition of createA to make a new A object, specifically one of type DerA (Error1: No instance of constructor "DerA::DerA" matches the argument list)
        return a; // Error2: Cannot return DerA for BaseA function
    }
}

So, I have two main problems, one is practical (Error1, as I seem to simply be calling the function wrong, even if I try to typecast this), one is philosophical (Error 2, as I don't know how to implement the features I want. If anyone could point out why Error1 is occurring, that would be wonderful! Error2, however, requires some explanation.

I would like my user (programmer) to interact with all A objects the same way. They will have the same exact public functions, but each will have VERY different implementations of these functions. Some will be using different data types (and so will require function contracts), but many will have the same data types just with different algorithms that they use on them. I would like some piece of code to work exactly the same way if one class A derivative is used or another is. However, in my current implementation, it seems that I need to return a DerA object instead of a BaseA object (at the site of Error2). This means that I will need to write a segment of main code SPECIFICALLY for a DerA object, instead of any arbitrary A object. I would like something like:

BaseB b = new DerB(); // Declare which derivative of BaseB I want to use
BaseA a = b->createA(b); // Call the createA function in that derivative, which will automatically make a corresponding A object

This way, I can simply choose which type of B object I would like in the first line (by my choice of B constructor, or tag, or template, or something), and the rest of the code will look the same for any type of object B (as each has the same public member functions, even though each object will perform those functions differently).

Would I be better off using templates or some other method instead of inheritance? (I apologize for being intentionally vague, but I hope my class A/B example should mostly explain what I need).

Thank you for any help. I apologize for asking two questions in one post and for being long-winded, but I am trying to learn the best way to approach a rather large redesign of some software.

Upvotes: 0

Views: 167

Answers (1)

Christophe
Christophe

Reputation: 73627

You have several syntactical issues to get the errors solved:

  • Add the ; after each class definitions.
  • The first line should be a forward declaration: class BaseB /*{} NO!!*/ ;
  • Add public: to make constructor of DerA accessible for DerB
  • BaseA createA() should return a value, not a pointner (according to signature): return *a;

There is another potential hidden slicing issue, as createA() returns a value, an not a pointer. This means that your returned object (here *a), would be copied but as a real BaseA object. So only the BaseA part of the object will be copied, not the derived part. This could lead to some unexpected surprises.

In order to avoid slicing, consider returning a pointer, changing the signature of createA() accordingly. The object pointed to would then keep the right type without loosing anything.

If you would later need to copy the object, you could use a static cast if you are absolutely sure of the real type of the object pointed to:

   BaseA *pba = pdb->createA();         // get pointer returned 
   DerA da = *static_cast<DerA*>(pba);  // static cast with pointer

If you would need to copy pointed BaseA objects without necessarily knwowing for sure their real type, you could implement a virtual clone function in DerA (e.g. prototype design pattern)

Upvotes: 2

Related Questions