Need to override workarounds

I find it difficult to find (which I am sure is very common) a design template to solve 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 class B does not override the pure virtual function 'foo'. The compiler considers foo that B declares only as an overload for foo, because codimension is not allowed in the input parameters when overriding 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 did not implement any type of parameter except BB.

Of course, I could just include aa in BB in the implementation of B foo, but I'm looking for a solution that preserves type safety and actually forces the class B implementer to also implement the class that inherits from AA in order to compile the code. In an ideal world, I could write something similar to 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 like this in C ++? (possibly using some kind of matching object without the need for inheritance)

Note that in fact (as opposed to the example), inheritance between BB and AA is crucial, since AA has many children who have many qualities, and in the end, what I want to do is iterate over the class vector A and run 'foo' with appropriate parameters only (vector AA)

+4
source share
2 answers

To ensure type safety, you should use patterns 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; } }; 

Further 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

+8
source

You can see the visitor template. this is a general solution to problems like “double sending” (sending to a virtual function based on the object and message).

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

edit: to clarify, this can help parse the goals 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 ). It is rather inconvenient to model or even think about conceptually.

To remake this as a visitor, you usually turn one of the hierarchies into one class and instead model the operations that you can perform in this class in the hierarchy of algorithms through the visitor. This is more robust because it forces you to explicitly implement each combination of the hierarchy relationships and will break at compile time (good) if you later change the hierarchy.

 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); } 
+3
source

All Articles