4

I'm having difficulty finding the (what I'm sure is a very common) design pattern to work around the following problem. Consider this piece of code:

class AA {};
class BB : public AA {};

class A
{
public:
    virtual void foo(AA& aa) = 0;
};

class B : A
{
public:
    void foo(BB& bb){cout<<"B::foo"<<endl;}
};

int main()
{
    B b;
    BB bb;
    b.foo(bb);
}

This code will not compile because the class B does not override the pure virtual function 'foo'. The compiler considers the foo that B declares only as an overload to foo because co-variance is not allowed in input parameters in overriden functions.

Now, I understand the reason for this. The fact that B inherits from A means that it should be able to handle any calls to foo with parameters of type AA, and the previous code gave no implementation to handle any parameter type except BB.

Of course I could just cast the aa to BB in B's foo implementation, but I'm looking for a solution that preserves type-safety and actually forces the implementer of B class to also implement a class that inherits from AA in order for the code to compile. In an ideal world I would be able to write something that looks like this pseudo-code:

class A
{
public:
    abstract class AA{}; //indicates that any child of A must implement also child of AA
    abstract void foo(AA& aa);
};

class B : public A
{
public:
    class BB : AA{}; //will not compile without this
    void foo(BB& bb){cout<<"B::foo"<<endl;}
};

Is there a way to achieve something similar to this in C++? (boost maybe, by some kind of mapping object without the need for inheritance)

Please note that in actuality (unlike in the example), inheritance between BB and AA is crucial as AA has many children that share many qualities, and in the end what I want to accomplish is to iterate over a vector of A classes and run 'foo' only with appropriate parameters (vector of AA's)

eladidan
  • 2,634
  • 2
  • 26
  • 39
  • 4
    are you intending to pass polymorphic objects by value? you will get slicing problems... you should be passing `AA& aa` and `BB& bb` – Cechner Aug 22 '11 at 08:42
  • Why does `foo` have to be virtual in this case? – Andreas Brinck Aug 22 '11 at 08:49
  • @Andreas: I want all classes that inherit from A to have to implement their own version of foo andtherefor it's pure virtual – eladidan Aug 22 '11 at 09:19
  • You probably wanted all your inheritances to be `public`, not (implicitly) `private`. Or else your problem won't make sense as e.g. a `BB&` won't implicitly convert to `AA&`, and you can't downcast a `AA&` to `BB&` without special access rights. – Luc Danton Aug 22 '11 at 09:28

2 Answers2

9

To provide type safety, you should use templates instead of inheritance.

class AA {};
class BB : AA {};

template <typename Managed> class FooManager {
    virtual void foo(Managed& m) { /* default implementation */ }
};

class B : public FooManager<BB> {
    void foo(BB bb) { cout << "B:foo()" << endl; }
};

Later in the code, for example, if you want to traverse an array,

template<typename Managed> void processAll(vector<Managed> v, FooManager<Managed> mgr) {
    for(Managed& m : v) mgr.foo(m);
}

B b;
vector<BB> bbs;
processAll(bbs, b);

Edit: typo fix

Maxim Razin
  • 9,114
  • 7
  • 34
  • 33
  • 1
    This was actually my previous design. The main flaw here is that you lose the metamorphism of foo. With this design you can't iterate over a vector of FooManager and AA's and safely call foo only when there is accordance because foo can have any type of parameter, not only of type derived from AA. I found this solution to be too weak for my team's needs – eladidan Aug 22 '11 at 09:23
  • @eladidan I think there are solutions to this 'flaw'. You can make sure the actual template parameter fits your requirements. – jv42 Aug 22 '11 at 11:40
  • embarrassing. at my previous comment I meant polymorphism and not metamorphism. Lesson learned. Never post a comment when you are hungry enough to eat your keyboard... – eladidan Aug 22 '11 at 12:14
  • @jv42: Could you expand? How would I go about doing that? (Perhaps write an answer...). Thanks – eladidan Aug 22 '11 at 12:15
  • 1
    @eladidan As I'm currently more into C#, I'd rather let C++ gurus explain the C++ implementation of 'template parameters constraints'. A search found this: http://stackoverflow.com/questions/122316/template-constraints-c – jv42 Aug 22 '11 at 12:19
  • @jv42: that seems like a very possible direction to go in. It appears that concept constraints have been removed from the c++0x standard, but boost have a library that deals with this:http://www.boost.org/doc/libs/1_36_0/libs/concept_check/concept_check.htm – eladidan Aug 22 '11 at 13:36
3

you could look at the visitor pattern. this is the general solution to 'double dispatch' type problems (dispatch to a virtual function based on the object and the message).

That is, put foo() into a visitor, and rename A::foo() to A::Visit(FooVisitor& ):

edit: to clarify, it might help to disentangle the purposes of your hierarchies. If you think about it, you are trying to model the relationship of one hierarchy (AA and BB) in terms of another (A and B). This is pretty awkward to model, or even to think about conceptually.

To remodel this as a visitor, you'd generally turn one of the hierarchies into a single class, and instead model the operations you can perform on that class in a hierarchy of algorithms via a visitor. This is more robust because it forces you to explicitly implement each combination of hierarchy relationships, and will break at compile-time (good) if you modify the hierarchy later on.

class A; class B;
struct AVisitor 
{ 
    virtual ~AVisitor() { } 

    virtual void Visit(A& ) = 0;
    virtual void Visit(B& ) = 0;
};

class A
{
public:
    virtual ~A() { }

    virtual void Visit(AVisitor & visitor) { visitor.Visit(*this); }
};

class B : public A
{
public:
    virtual void Visit(AVisitor & visitor) { visitor.Visit(*this); }
};

struct PrintingVisitor : public AVisitor
{
    void Visit(A& a){cout<<"A::foo"<<endl;}
    void Visit(B& b){cout<<"B::foo"<<endl;}
};

int main()
{
    B b;
    PrintingVisitor printer;
    b.Visit(printer);
}
Cechner
  • 849
  • 7
  • 19
  • This solution doesn't translate well into the domain of my problem since in my case classes derived from A are in themselves algorithmic objects and foo is their main function which runs the algorithm on an input of type derived from AA. Removing the main algorithm from them nullifies the use of that class hierarchy completely. Further more there will be no more than a single implementation of foo for each child of A, so I will never create more than one child of AVisitor – eladidan Aug 22 '11 at 13:33
  • fair enough - if you don't want to abstract away the foo operation the visitor loses much of its usefulness. If you don't want to treat the algorithms polymorphically though, inheritance is probably not the right approach... perhaps something template-y along the lines of grep's answer above is more suited – Cechner Aug 22 '11 at 13:43
  • @eladian, have you considered making the `A` hierarchy [Strategies](http://en.wikipedia.org/wiki/Strategy_pattern)? That is, `FooStrategyA` and `FooStrategyB`, that are passed to the `BB` ctor and used directly by `BB`? – Cechner Aug 23 '11 at 00:05
  • Strategies DP is redundant for our design since foo is really the only significant action for classes derived from A. Perhaps I should explain my problem-space a little less obscurely, if I want better answers. I'm designing a pipe of filters, very similar to that of DirectShow filters, only the pipe is static at run-time. The A class is the BaseFilter class (pure-virtual) and classes derived from it are filter implementations. The AA class is the base I/O class, and each filter has different input/output. I'm currently looking in to the DirectShow design for reference – eladidan Aug 25 '11 at 08:23