I need to store a container of pointers to objects.
These objects have some common methods/attributes (interface) that I want to enforce (possibly at compile time) and use.
Example:
struct A{
void fly(){}
};
struct B{
void fly(){}
};
A a;
B b;
std::vector<some *> objects;
objects.push_back(&a);
objects.push_back(&b);
for(auto & el: objects)
el->fly();
The simpler solution would be A and B inherit a common base class like FlyingClass:
struct FlyingClass{
void fly(){}
};
struct A: public FlyingClass { ...
struct B: public FlyingClass { ...
and create a
std::vector<FlyingClass *> objects;
This will work and also enforce the fact that I can only add to objects things that can fly (implement FlyingClass).
But what if I need to implement some other common methods/attributes WITHOUT coupling them with the above base class?
Example:
struct A{
void fly(){}
void swim(){}
};
struct B{
void fly(){}
void swim(){}
};
And i would like to do:
for(auto & el: objects) {
el->fly();
...
el->swim();
...
}
More in general i would be able to call a function passing one of these pointers and access both the common methods/attributes, like:
void dostuff(Element * el){
el->fly();
el->swim();
}
I could try to inherit from another interface like:
struct SwimmingClass{
void swim(){}
};
struct A: public FlyingClass, public SwimmingClass { ...
struct B: public FlyingClass, public SwimmingClass { ...
But then what the container should contain?
std::vector<FlyingClass&&SwimmingClass *> objects;
Sure, i could implement SwimmingFlyingClass, but what if i need RunningClass etc.. This is going to be a nightmare.
In other words, how can I implement a pointer to multiple interfaces without coupling them?
Or there is some template way of rethinking the problem?
Even run time type information could be acceptable in my application, if there is an elegant and maintainable way of doing this.
It is possible to do this, in a pretty TMP-heavy way that's a little expensive at runtime. A redesign is favourable so that this is not required. The long and short is that what you want to do isn't possible cleanly without language support, which C++ does not offer.
As for the ugly, shield your eyes from this:
struct AnyBase { virtual ~AnyBase() {} }; // All derived classes inherit from.
template<typename... T> class Limited {
AnyBase* object;
template<typename U> Limited(U* p) {
static_assert(all<is_base_of<T, U>...>::value, "Must derive from all of the interfaces.");
object = p;
}
template<typename U> U* get() {
static_assert(any<is_same<U, T>...>::value, "U must be one of the interfaces.");
return dynamic_cast<U*>(object);
}
}
Some of this stuff isn't defined as Standard so I'll just run through it. The static_assert on the constructor enforces that U inherits from all of T. I may have U and T the wrong way round, and the definition of all is left to the reader.
The getter simply requires that U is one of the template arguments T.... Then we know in advance that the dynamic_cast will succeed, because we checked the constraint statically.
It's ugly, but it should work. So consider
std::vector<Limited<Flying, Swimming>> objects;
for(auto&& obj : objects) {
obj.get<Flying>()->fly();
obj.get<Swimming>()->swim();
}
You are asking for something which doesn't make sense in general, that's why there is no easy way to do it.
You are asking to be able to store heterogeneus objects in a collection, with interfaces that are even different.
How are you going to iterate over the collections without knowing the type? You are restricted to the least specific or forced to do dynamic_cast pointers and cross fingers.
class Entity { }
class SwimmingEntity : public Entity {
virtual void swim() = 0;
}
class FlyingEntity : public Entity {
virtual void fly() = 0;
}
class Fish : public SwimmingEntity {
void swim() override { }
}
class Bird : public FlyingEntity {
void fly() override { }
}
std:vector<Entity*> entities;
This is legal but doesn't give you any information to the capabilities of the runtime Entity instance. It won't lead anywhere unless you work them out with dynamic_cast and rtti (or manual rtti) so where's the advantage?
This is pretty much a textbook example calling for type erasure.
The idea is to define an internal abstract (pure virtual) interface class that captures the common behavior(s) you want, then to use a templated constructor to create a proxy object derived from that interface:
#include <iostream>
#include <vector>
#include <memory>
using std::cout;
struct Bird {
void fly() { cout << "Bird flies\n"; }
void swim(){ cout << "Bird swims\n"; }
};
struct Pig {
void fly() { cout << "Pig flies!\n"; }
void swim() { cout << "Pig swims\n"; }
};
struct FlyingSwimmingThing {
// Pure virtual interface that knows how to fly() and how to swim(),
// but does not depend on type of underlying object.
struct InternalInterface {
virtual void fly() = 0;
virtual void swim() = 0;
virtual ~InternalInterface() { }
};
// Proxy inherits from interface; forwards to underlying object.
// Template class allows proxy type to depend on object type.
template<typename T>
struct InternalImplementation : public InternalInterface {
InternalImplementation(T &obj) : obj_(obj) { }
void fly() { obj_.fly(); }
void swim() { obj_.swim(); }
virtual ~InternalImplementation() { }
private:
T &obj_;
};
// Templated constructor
template<typename T>
FlyingSwimmingThing(T &obj) : proxy_(new InternalImplementation<T>(obj))
{ }
// Forward calls to underlying object via virtual interface.
void fly() { proxy_->fly(); }
void swim() { proxy_->swim(); }
private:
std::unique_ptr<InternalInterface> proxy_;
};
int main(int argc, char *argv[])
{
Bird a;
Pig b;
std::vector<FlyingSwimmingThing> objects;
objects.push_back(FlyingSwimmingThing(a));
objects.push_back(FlyingSwimmingThing(b));
objects[0].fly();
objects[1].fly();
objects[0].swim();
objects[1].swim();
}
The same trick is used for the deleter in a shared_ptr and for std::function. The latter is arguably the poster child for the technique.
You will always find a call to "new" in there somewhere. Also, if you want your wrapper class to hold a copy of the underlying object rather than a pointer, you will find you need a clone() function in the abstract interface class (whose implementation will also call new). So these things can get very non-performant very easily, depending on what you are doing...
[Update]
Just to make my assumptions clear, since some people appear not to have read the question...
You have multiple classes implementing fly() and swim() functions, but that is all that the classes have in common; they do not inherit from any common interface classes.
The goal is to have a wrapper object that can store a pointer to any one of those classes, and through which you can invoke the fly() and swim() functions without knowing the wrapped type at the call site. (Take the time to read the question to see examples; e.g. search for dostuff.) This property is called "encapsulation"; that is, the wrapper exposes the fly() and swim() interfaces directly and it can hide any properties of the wrapped object that are not relevant.
Finally, it should be possible to create a new otherwise-unrelated class with its own fly() and swim() functions and have the wrapper hold a pointer to that class (a) without modifying the wrapper class and (b) without touching any call to fly() or swim() via the wrapper.
These are, as I said, textbook features of type erasure. I did not invent the idiom, but I do recognize when it is called for.
Related
I am trying to understand the internals of https://github.com/vshymanskyy/TinyGSM/tree/master/src and am confused with how the classes are constructed.
In particular I see that in TinyGsmClientBG96.h they define a class that inherits from multiple templated parent classes.
class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
public TinyGsmGPRS<TinyGsmBG96>,
public TinyGsmTCP<TinyGsmBG96, TINY_GSM_MUX_COUNT>,
public TinyGsmCalling<TinyGsmBG96>,
public TinyGsmSMS<TinyGsmBG96>,
public TinyGsmTime<TinyGsmBG96>,
public TinyGsmGPS<TinyGsmBG96>,
public TinyGsmBattery<TinyGsmBG96>,
public TinyGsmTemperature<TinyGsmBG96>
Fair enough. If I look at one of these, for example TinyGsmTemperature, I find some confusing code.
It looks like the static cast is in place so the we can call the hardware agnostic interface getTemperature() and use the implementation defined in TinyGsmBG96.
Why not use function overriding in this case?
What is the thinking behind this implementation?
Is this a common pattern in c++?
template <class modemType>
class TinyGsmTemperature
{
public:
/*
* Temperature functions
*/
float getTemperature()
{
return thisModem().getTemperatureImpl();
}
/*
* CRTP Helper
*/
protected:
inline const modemType &thisModem() const
{
return static_cast<const modemType &>(*this);
}
inline modemType &thisModem()
{
return static_cast<modemType &>(*this);
}
float getTemperatureImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
};
Is this a common pattern in c++?
Yes, it is called CRTP - curiously recurring template pattern.
Why not use function overriding in this case?
override relies on virtual tables, causing extra runtime overhead.
What is the thinking behind this implementation?
Say, we want a class hierarchy with overridable methods. The classic OOP approach is virtual functions. However, they aren't zero-cost: when you have
void foo(Animal& pet) { pet.make_noise(); }
you don't statically know (in general) which implementation has been passed to foo() because you've erased its type from Dog (or Cat? or something else?) to Animal. So, the OOP approach uses virtual tables to find the right function at runtime.
How do we avoid this? We can instead remember the derived type statically:
template<typename Derived /* here's where we keep the type */> struct Animal {
void make_noise() {
// we statically know we're a Derived - no runtime dispatch!
static_cast<Derived&>(*this).make_noise();
}
};
struct Dog: public Animal<Dog /* here's how we "remember" the type */> {
void make_noise() { std::cout << "Woof!"; }
};
Now, let's rewrite foo() in a zero-cost manner:
template<typename Derived> void foo(Animal<Derived>& pet) { pet.make_noise(); }
Unlike the first attempt, we haven't erased the type from ??? to Animal: we know Animal<Derived> is actually a Derived, which is a templated - therefore, fully known to the compiler - type. This turns the virtual function call into a direct one (so, even allows inlining).
I need a way to provide different interfaces from a single object.
For example. User one should be able to call Foo::bar() and user 2 should be able to call Foo::baz() but user one cannot call Foo::baz() and respectively user two cannot call Foo::bar().
I did manage to do this but I don't think that it's optimal.
class A
{
public:
virtual void bar() = 0;
virtual ~A() = 0;
};
class B
{
public:
virtual void baz() = 0;
virtual ~B() = 0;
};
class Foo : public A, public B
{
public:
Foo() = default;
void baz() override;
void bar() override;
};
class Factory
{
public:
Factory()
{
foo = std::make_shared<Foo>();
}
std::shared_ptr<A> getUserOne()
{
return foo;
}
std::shared_ptr<B> getUserTwo()
{
return foo;
}
private:
std::shared_ptr<Foo> foo;
};
Is there a better way to achieve this. Maybe with wrapper objects. I don't really need to allocate this foo object with new(std::make_shared) I even prefer not to, but I cannot use raw pointers and smart pointers give unnecessary overhead and system calls.
Edit: I'll try to give an example.
There is a car. User one is the driver. He can steer the wheel, accelerate or use the breaks. User two is the passenger and he can control the radio for example.
I don't want the passenger to be able to use the breaks or the driver to be able to use the radio.
Also they are both in the car so the actions of user one will have effect on user two and vice versa.
What you essentially need is a shared data between two objects. The inheritance is not a very good choice for this because not only you do not need is A relationship but you explicitely want to avoid it. Therefore composition is your answer, especially since you have a factory:
class Data
{
public:
void bar();
void baz();
};
Then instead of inheritance you would use composition:
class A
{
public:
A(Base *base) : mBase(base) {}
void bar() { mBase->bar(); }
private:
Base *mBase = nullptr;
};
//class B would be the same only doing baz()
Finally the Factory:
class Factory
{
public:
A *getUserOne() { return &mA; }
B *getUserTwo() { return &mB; }
private:
Base mBase;
A mA(&mBase);
B mB(&mBase);
};
Couple of points about this solution. While it does not allocate on the heap you will need to keep the Factory alive as long as there are users of it. For this reason the use of std::shared_ptr as in the OP might be a smart idea. :-) But comes of course with the cost of the atomic reference counting.
Secondly A is not related to B in any way. This is by design and unlike the original solution does not allow dynamic_cast between A and B.
Lastly where the implementation will be is up to you. You can have it all in Data and have A and B merely call it (as in above) but you can also make Data into just a struct holding only your data and have the implementation of your methods in A and B respectively. The latter is more "data oriented" programming that has a lots of popularity these days as opposed to more traditional "object oriented" which is what I chose to demonstrate.
You can declare your data separately
struct Data
{
/* member variables */
};
Have an interface class capable of manipulating said data will all members protected
class Interface
{
protected:
Interface(Data &data) : m_data{data} {}
void bar() { /* implementation */ }
void baz() { /* implementation */ }
Data &m_data;
};
Have derived classed that make public specific members
class A : private Interface
{
public:
A(Data &data) : Interface{data} {}
using Interface::bar;
};
class B : private Interface
{
public:
B(Data &data) : Interface{data} {}
using Interface::baz;
};
This way you can also have users capable of having overlapping access to some functionality without having to implement it multiple times.
class Admin : private Interface
{
public:
Admin(Data &data) : Interface{data} {}
using Interface::bar;
using Interface::baz;
};
Of course, depending on how you're using the data, you might want a pointer or shared pointer, possibly add some syncronization between accesses from multiple threads.
Sample code using this model:
void test()
{
Data d{};
auto a = A{d};
a.bar();
// a.baz is protected so illegal to call here
auto b = B{d};
b.baz();
// b.bar is protected so illegal to call here
auto admin = Admin{d};
admin.bar();
admin.baz();
}
This seems to me efficient in the sense that you only have one set of data and a single implementation for data manipulation, no matter how many user types you have.
Let's say I have a parent class, Arbitrary, and two child classes, Foo and Bar. I'm trying to implement a function to insert any Arbitrary object into a database, however, since the child classes contain data specific to those classes, I need to perform slightly different operations depending on the type.
Coming into C++ from Java/C#, my first instinct was to have a function that takes the parent as the parameter use something like instanceof and some if statements to handle child-class-specific behavior.
Pseudocode:
void someClass(Arbitrary obj){
obj.doSomething(); //a member function from the parent class
//more operations based on parent class
if(obj instanceof Foo){
//do Foo specific stuff
}
if(obj instanceof Bar){
//do Bar specific stuff
}
}
However, after looking into how to implement this in C++, the general consensus seemed to be that this is poor design.
If you have to use instanceof, there is, in most cases, something wrong with your design. – mslot
I considered the possibility of overloading the function with each type, but that would seemingly lead to code duplication. And, I would still end up needing to handle the child-specific behavior in the parent class, so that wouldn't solve the problem anyway.
So, my question is, what's the better way of performing operations that where all parent and child classes should be accepted as input, but in which behavior is dictated by the object type?
First, you want to take your Arbitrary by pointer or reference, otherwise you will slice off the derived class. Next, sounds like a case of a virtual method.
void someClass(Arbitrary* obj) {
obj->insertIntoDB();
}
where:
class Arbitrary {
public:
virtual ~Arbitrary();
virtual void insertIntoDB() = 0;
};
So that the subclasses can provide specific overrides:
class Foo : public Arbitrary {
public:
void insertIntoDB() override
// ^^^ if C++11
{
// do Foo-specific insertion here
}
};
Now there might be some common functionality in this insertion between Foo and Bar... so you should put that as a protected method in Arbitrary. protected so that both Foo and Bar have access to it but someClass() doesn't.
In my opinion, if at any place you need to write
if( is_instance_of(Derived1) )
//do something
else if ( is_instance_of(Derived2) )
//do somthing else
...
then it's as sign of bad design. First and most straight forward issue is that of "Maintainence". You have to take care in case further derivation happens. However, sometimes it's necessary. for e.g if your all classes are part of some library. In other cases you should avoid this coding as far as possible.
Most often you can remove the need to check for specific instance by introducing some new classes in the hierarchy. For e.g :-
class BankAccount {};
class SavingAccount : public BankAccount { void creditInterest(); };
class CheckingAccount : public BankAccount { void creditInterest(): };
In this case, there seems to be a need for if/else statement to check for actual object as there is no corresponsing creditInterest() in BanAccount class. However, indroducing a new class could obviate the need for that checking.
class BankAccount {};
class InterestBearingAccount : public BankAccount { void creditInterest(): } {};
class SavingAccount : public InterestBearingAccount { void creditInterest(): };
class CheckingAccount : public InterestBearingAccount { void creditInterest(): };
The issue here is that this will arguably violate SOLID design principles, given that any extension in the number of mapped classes would require new branches in the if statement, otherwise the existing dispatch method will fail (it won't work with any subclass, just those it knows about).
What you are describing looks well suited to inheritance polymorphicism - each of Arbitrary (base), Foo and Bar can take on the concerns of its own fields.
There is likely to be some common database plumbing which can be DRY'd up the base method.
class Arbitrary { // Your base class
protected:
virtual void mapFields(DbCommand& dbCommand) {
// Map the base fields here
}
public:
void saveToDatabase() { // External caller invokes this on any subclass
openConnection();
DbCommand& command = createDbCommand();
mapFields(command); // Polymorphic call
executeDbTransaction(command);
}
}
class Foo : public Arbitrary {
protected: // Hide implementation external parties
virtual void mapFields(DbCommand& dbCommand) {
Arbitrary::mapFields();
// Map Foo specific fields here
}
}
class Bar : public Arbitrary {
protected:
virtual void mapFields(DbCommand& dbCommand) {
Arbitrary::mapFields();
// Map Bar specific fields here
}
}
If the base class, Arbitrary itself cannot exist in isolation, it should also be marked as abstract.
As StuartLC pointed out, the current design violates the SOLID principles. However, both his answer and Barry's answer has strong coupling with the database, which I do not like (should Arbitrary really need to know about the database?). I would suggest that you make some additional abstraction, and make the database operations independent of the the data types.
One possible implementation may be like:
class Arbitrary {
public:
virtual std::string serialize();
static Arbitrary* deserialize();
};
Your database-related would be like (please notice that the parameter form Arbitrary obj is wrong and can truncate the object):
void someMethod(const Arbitrary& obj)
{
// ...
db.insert(obj.serialize());
}
You can retrieve the string from the database later and deserialize into a suitable object.
So, my question is, what's the better way of performing operations
that where all parent and child classes should be accepted as input,
but in which behavior is dictated by the object type?
You can use Visitor pattern.
#include <iostream>
using namespace std;
class Arbitrary;
class Foo;
class Bar;
class ArbitraryVisitor
{
public:
virtual void visitParent(Arbitrary& m) {};
virtual void visitFoo(Foo& vm) {};
virtual void visitBar(Bar& vm) {};
};
class Arbitrary
{
public:
virtual void DoSomething()
{
cout<<"do Parent specific stuff"<<endl;
}
virtual void accept(ArbitraryVisitor& v)
{
v.visitParent(*this);
}
};
class Foo: public Arbitrary
{
public:
virtual void DoSomething()
{
cout<<"do Foo specific stuff"<<endl;
}
virtual void accept(ArbitraryVisitor& v)
{
v.visitFoo(*this);
}
};
class Bar: public Arbitrary
{
public:
virtual void DoSomething()
{
cout<<"do Bar specific stuff"<<endl;
}
virtual void accept(ArbitraryVisitor& v)
{
v.visitBar(*this);
}
};
class SetArbitaryVisitor : public ArbitraryVisitor
{
void visitParent(Arbitrary& vm)
{
vm.DoSomething();
}
void visitFoo(Foo& vm)
{
vm.DoSomething();
}
void visitBar(Bar& vm)
{
vm.DoSomething();
}
};
int main()
{
Arbitrary *arb = new Foo();
SetArbitaryVisitor scv;
arb->accept(scv);
}
Browsing in a code base I found something on the line of:
class Interface{
public:
virtual void func() = 0;
};
class Implementation : public Interface{
protected:
void func() override {};
};
I thought that would have been a compilation error, but it seems it is not. What sense does it make?
In C++:
accessibility is a “static” notion (checked at compile-time), whereas
virtual dispatch is a “dynamic” notion (the implementation to call is chosen at run-time).
We can say that C++ keeps those two notions “orthogonal”.
So with your example, this will compile (not realistic code, just illustration):
Implementation obj;
Interface& ref = obj;
ref.func(); // (will call obj.func())
but this won't:
Implementation obj;
obj.func(); // error: Implementation::func is protected
effectively “forcing” you to only use the interface (which maybe was the intent). — Edit: see Dieter Lücking's answer for a maybe better design.
Freedom. Sometimes it may be kind of useful (for example if you want to hide a member you want to discourage to be used). At least when they access through derived class.
See it as kind of "explicit implementation". Let's say, for example, you have a base interface List like this (very simplified code for illustration purposes):
class List {
public:
virtual void add(std::string item) = 0;
virtual std::string at(int index) = 0;
};
You create your ReadOnlyList concrete class which implements List interface, in this case you would discourage users of your class to call add() method, just change its visibility. Unless they're accessing it through List interface it'll be hidden.
Another example? If you want to provide an interface for some specific tasks but it's an implementation detail and it's not part of class contract. In this case you make them protected or private and they won't be accessible.
That said it's so weak and confusing that I would avoid to do it, besides very few, commented and well controlled exceptions.
What sense does it make?
Yes, it makes sense. If you try to create object of Derived type, you will not be able to call that method. So the idea is to always access the object through it's interface.
The idea is to enforce the Interface segregation principle.
#include <iostream>
#include <vector>
#include <memory>
struct Base
{
public:
virtual ~Base(){}
virtual void foo() = 0;
};
struct Derived1 : Base
{
protected:
virtual void foo(){
std::cout << "foo 1" << std::endl;
}
};
struct Derived2 : Base
{
protected:
virtual void foo(){
std::cout << "foo 2" << std::endl;
}
};
void wouldFail()
{
Derived1 d;
// d.foo(); -- Error! Do not try to call it directly
}
void ok()
{
std::vector< std::shared_ptr< Base > > v;
v.emplace_back( std::make_shared<Derived1>() );
v.emplace_back( std::make_shared<Derived2>() );
for ( auto & it : v )
it->foo();
}
int main()
{
wouldFail();
ok();
}
I'm finding it difficult to describe this problem very concisely, so I've attached the code for a demonstration program.
The general idea is that we want a set of Derived classes that are forced to implement some abstract Foo() function from a Base class. Each of the derived Foo() calls must accept a different parameter as input, but all of the parameters should also be derived from a BaseInput class.
We see two possible solutions so far, neither we're very happy with:
Remove the Foo() function from the base class and reimplement it with the correct input types in each Derived class. This, however, removes the enforcement that it be implemented in the same manner in each derived class.
Do some kind of dynamic cast inside the receiving function to verify that the type received is correct. However, this does not prevent the programmer from making an error and passing the incorrect input data type. We would like the type to be passed to the Foo() function to be compile-time correct.
Is there some sort of pattern that could enforce this kind of behaviour? Is this whole idea breaking some sort of fundamental idea underlying OOP? We'd really like to hear your input on possible solutions outside of what we've come up with.
Thanks so much!
#include <iostream>
// these inputs will be sent to our Foo function below
class BaseInput {};
class Derived1Input : public BaseInput { public: int d1Custom; };
class Derived2Input : public BaseInput { public: float d2Custom; };
class Base
{
public:
virtual void Foo(BaseInput& i) = 0;
};
class Derived1 : public Base
{
public:
// we don't know what type the input is -- do we have to try to cast to what we want
// and see if it works?
virtual void Foo(BaseInput& i) { std::cout << "I don't want to cast this..." << std::endl; }
// prefer something like this, but then it's not overriding the Base implementation
//virtual void Foo(Derived1Input& i) { std::cout << "Derived1 did something with Derived1Input..." << std::endl; }
};
class Derived2 : public Base
{
public:
// we don't know what type the input is -- do we have to try to cast to what we want
// and see if it works?
virtual void Foo(BaseInput& i) { std::cout << "I don't want to cast this..." << std::endl; }
// prefer something like this, but then it's not overriding the Base implementation
//virtual void Foo(Derived2Input& i) { std::cout << "Derived2 did something with Derived2Input..." << std::endl; }
};
int main()
{
Derived1 d1; Derived1Input d1i;
Derived2 d2; Derived2Input d2i;
// set up some dummy data
d1i.d1Custom = 1;
d2i.d2Custom = 1.f;
d1.Foo(d2i); // this compiles, but is a mistake! how can we avoid this?
// Derived1::Foo() should only accept Derived1Input, but then
// we can't declare Foo() in the Base class.
return 0;
}
Since your Derived class is-a Base class, it should never tighten the base contract preconditions: if it has to behave like a Base, it should accept BaseInput allright. This is known as the Liskov Substitution Principle.
Although you can do runtime checking of your argument, you can never achieve a fully type-safe way of doing this: your compiler may be able to match the DerivedInput when it sees a Derived object (static type), but it can not know what subtype is going to be behind a Base object...
The requirements
DerivedX should take a DerivedXInput
DerivedX::Foo should be interface-equal to DerivedY::Foo
contradict: either the Foo methods are implemented in terms of the BaseInput, and thus have identical interfaces in all derived classes, or the DerivedXInput types differ, and they cannot have the same interface.
That's, in my opinion, the problem.
This problem occured to me, too, when writing tightly coupled classes that are handled in a type-unaware framework:
class Fruit {};
class FruitTree {
virtual Fruit* pick() = 0;
};
class FruitEater {
virtual void eat( Fruit* ) = 0;
};
class Banana : public Fruit {};
class BananaTree {
virtual Banana* pick() { return new Banana; }
};
class BananaEater : public FruitEater {
void eat( Fruit* f ){
assert( dynamic_cast<Banana*>(f)!=0 );
delete f;
}
};
And a framework:
struct FruitPipeLine {
FruitTree* tree;
FruitEater* eater;
void cycle(){
eater->eat( tree->pick() );
}
};
Now this proves a design that's too easily broken: there's no part in the design that aligns the trees with the eaters:
FruitPipeLine pipe = { new BananaTree, new LemonEater }; // compiles fine
pipe.cycle(); // crash, probably.
You may improve the cohesion of the design, and remove the need for virtual dispatching, by making it a template:
template<class F> class Tree {
F* pick(); // no implementation
};
template<class F> class Eater {
void eat( F* f ){ delete f; } // default implementation is possible
};
template<class F> PipeLine {
Tree<F> tree;
Eater<F> eater;
void cycle(){ eater.eat( tree.pick() ); }
};
The implementations are really template specializations:
template<> class Tree<Banana> {
Banana* pick(){ return new Banana; }
};
...
PipeLine<Banana> pipe; // can't be wrong
pipe.cycle(); // no typechecking needed.
You might be able to use a variation of the curiously recurring template pattern.
class Base {
public:
// Stuff that don't depend on the input type.
};
template <typename Input>
class Middle : public Base {
public:
virtual void Foo(Input &i) = 0;
};
class Derived1 : public Middle<Derived1Input> {
public:
virtual void Foo(Derived1Input &i) { ... }
};
class Derived2 : public Middle<Derived2Input> {
public:
virtual void Foo(Derived2Input &i) { ... }
};
This is untested, just a shot from the hip!
If you don't mind the dynamic cast, how about this:
Class BaseInput;
class Base
{
public:
void foo(BaseInput & x) { foo_dispatch(x); };
private:
virtual void foo_dispatch(BaseInput &) = 0;
};
template <typename TInput = BaseInput> // default value to enforce nothing
class FooDistpatch : public Base
{
virtual void foo_dispatch(BaseInput & x)
{
foo_impl(dynamic_cast<TInput &>(x));
}
virtual void foo_impl(TInput &) = 0;
};
class Derived1 : public FooDispatch<Der1Input>
{
virtual void foo_impl(Der1Input & x) { /* your implementation here */ }
};
That way, you've built the dynamic type checking into the intermediate class, and your clients only ever derive from FooDispatch<DerivedInput>.
What you are talking about are covariant argument types, and that is quite an uncommon feature in a language, as it breaks your contract: You promised to accept a base_input object because you inherit from base, but you want the compiler to reject all but a small subset of base_inputs...
It is much more common for programming languages to offer the opposite: contra-variant argument types, as the derived type will not only accept everything that it is bound to accept by the contract, but also other types.
At any rate, C++ does not offer contravariance in argument types either, only covariance in the return type.
C++ has a lot of dark areas, so it's hard to say any specific thing is undoable, but going from the dark areas I do know, without a cast, this cannot be done. The virtual function specified in the base class requires the argument type to remain the same in all the children.
I am sure a cast can be used in a non-painful way though, perhaps by giving the base class an Enum 'type' member that is uniquely set by the constructor of each possible child that might possibly inherit it. Foo() can then check that 'type' and determine which type it is before doing anything, and throwing an assertion if it is surprised by something unexpected. It isn't compile time, but it's the closest a compromise I can think of, while still having the benefits of requiring a Foo() be defined.
It's certainly restricted, but you can use/simulate coviarance in constructors parameters.