I'm working on a complex notification system, in the process I noticed that users will probably have to implement possibly very large nested switches. I may be falling victim of premature optimization here (not efficiency, more like readability), because maybe that's fine and completely acceptable.
What I was trying to do was set up my classes in such a way where a base class pointer/reference could be used in a switch. My example below shows what I mean, and this works easily with a pure virtual conversion operator that returns an enumeration type.
e.g. Everything public...
1 2 3 4
|
class Base
{
virtual operator ChildTypeEnum()const = 0;
};
|
Then in use:
1 2 3 4 5 6 7 8 9 10
|
void Func(Base& base)
{
switch(base)
{
case childTypeOne: //...
case childTypeTwo: //...
//...
case childTypeN: //...
}
}
|
Ok so I've got the root switch figured out. Now, what I really wanted to do, was have a way to then get a reference to the Child of that types interface, from the reference or pointer that I know is of that Type.
I've tried several different things. Since C++ allows for a virtual function to return to override and have a different return type I thought I would just create a virtual operator() that returns a reference to the child's type (
without a cast).
e.g.
1 2 3
|
class Base
{
virtual Base& operator()= 0;
|
Then in child...
1 2 3 4 5
|
class Child
{
virtual Child& operator()(){
return *this;
}
|
This is fine, but it does not work, If I tried to do...
in main:
Child &child = somebaseref(); //It complains about converting a Base& to Child&
The example above ^ confuses me. Because it is polymorphic, it calls the childs operator() which returns a reference to
Child
...
*this
. But it "acts" like it is returning a reference to Base&, the return type seems to work like default values in a virtual function (uses the default value of the static type and not the dynamic type of the object)?
I also tried the template approach (template member function not template class). This works with a cast, which I was trying to avoid, but maybe this is the approach I will need to use, either way I don't think there is any way out of a cast (maybe I'm wrong?).
Here is a more complete example of what I am trying to do...
1 2 3 4 5 6 7 8 9 10 11
|
class Vehicle
{
public:
virtual operator VehicleTypes()const = 0;
virtual Vehicle& operator()() = 0; //<-- Really wanted to use something like this...
virtual ~Vehicle(){}
//virtual operator const Car&(){};
template<typename T> T* AsType(); //I have to use a cast here...
private:
};
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
|
class Car : public Vehicle
{
public:
//Override for using in switches...
virtual operator VehicleTypes()const{
return car;
}
//Have to use cast from Base...
virtual Car& operator()(){
return *this;
}
//Thought maybe I could use a type convertion
/*virtual operator const Car&()const{
return *this;
}*/
virtual bool SedanSpecificStuff()const{ return true; }
virtual void CoupeSpecificFunc()const{ /*some implementation*/}
};
class Truck : public Vehicle
{
public:
virtual operator VehicleTypes()const{
return truck;
}
virtual Truck& operator()(){
return *this;
}
virtual void SpecificTruckOperation()const{/*Truck implementation*/}
};
template<typename T>
T * Vehicle::AsType()
{
return dynamic_cast<T *>(this);
}
//Main is just for testing the sample here is crap.
int _tmain(int argc, _TCHAR* argv[])
{
Vehicle * vehicle = new Car;
switch(*vehicle)
{
case car:
{
std::cout << "Type is a car" << std::endl;
Car * pcar = vehicle->AsType<Car>();
if(pcar)
pcar->SedanSpecificStuff();
}
break;
case truck:
std::cout << "Type is a truck" << std::endl;
break;
default:
break;
}
delete vehicle;
return 0;
}
|
I'm basically trying to make it so users can make use of the interfaces, elegantly and intuitively.
e.g.
1 2 3 4 5 6 7 8 9 10 11
|
switch(base)
{
case childtype1:
{
base().ChildType1FunctionOne(); //ChildType1FunctionOne is not inherited from Base, it's only of child type1
base().ChildType1FuncTwo(); //same
}
case childtypeN:
{
base().ChildTypeNOperation9000();
//...
|
Is this possible?