Base Class pointer/reference to Derived type Objects - conversions without cast?

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?
Logical "switching" based on the data type of the variable can be done with a "try(), catch()" block although this really isn't what it is intended for. Otherwise simply overloading a callback function with different data types as arguments might accomplish what you are trying to do but you'd have to return a static void pointer of some kind which would then have to be cast by the end user and this method can get a little messy with memory allocation.
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.


It looks to me you're trying to create some events/handlers?

I've pasted a code form my project in this thread:
http://www.cplusplus.com/forum/general/70012/

Have a look to see an example on how to use it.


Here is the same generic thing:
This is actually implementation of oberver patern (uncomplete)

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#pragma once
#include <map>
#include <utility>

namespace events
{
	template <typename ReturnT, typename ParamT>
	class HandlerBase
	{
	public:
		virtual ReturnT Process(ParamT message) = 0;
	};


	template <typename TargetT, typename ReturnT, typename ParamT>
	class Handler : public HandlerBase<ReturnT,ParamT>
	{
	private:
		typedef ReturnT (TargetT::*method_t)(ParamT);
		TargetT* mObject;
		method_t mMethod;

	public:
		Handler(TargetT* object, method_t method)
			: mObject(object), mMethod(method) { }

		ReturnT Process(ParamT param) override
		{
			return (mObject->*mMethod)(param);
		}
	};


	template <typename ReturnT,typename ParamT>
	class Event
	{
	private:
		typedef std::multimap<long, HandlerBase<ReturnT,ParamT>*> eventMap;

		long id;
		static long counter;
		static eventMap mapper;
		typename static eventMap::iterator iter;

		static eventMap StartMapping()
		{
			eventMap temp;
			return temp;
		}

	public:
		Event() : id(++counter) { };

		~Event()
		{
			for(iter = mapper.find(id); iter != mapper.end(); iter = mapper.find(id))
			{
				delete iter->second;
				mapper.erase(iter);
			}
		}

		template<typename TargetT>
		void attach(TargetT* object, ReturnT (TargetT::*method)(ParamT))
		{
			mapper.insert(std::make_pair(id, new Handler<TargetT, ReturnT, ParamT>(object, method)));
		}

		void Emit(ParamT param)
		{
			for(iter = mapper.begin(); iter != mapper.end(); ++iter)
				if (iter->first == id)
					iter->second->Process(param);
		}
	};
	template<typename ReturnT,typename ParamT> 
	long Event<typename ReturnT,typename ParamT>::counter = 0;

	template<typename ReturnT,typename ParamT>
	typename Event<typename ReturnT,typename ParamT>::eventMap::iterator
		Event<typename ReturnT,typename ParamT>::iter = Event<typename ReturnT,typename ParamT>::mapper.begin();

	template<typename ReturnT,typename ParamT> 
	typename Event<typename ReturnT,typename ParamT>::eventMap
		Event<typename ReturnT,typename ParamT>::mapper(Event<typename ReturnT,typename ParamT>::StartMapping());


	template<typename ReturnT,typename ParamT>
	class Object
	{
	protected:
		virtual ~Object() = 0 { }

	public:
		template<typename TargetT>
		void Register(Event<ReturnT, ParamT>& evn, ReturnT (TargetT::*method)(ParamT))
		{
			evn.attach(dynamic_cast<TargetT*>(this), method);
		}
	};
}


It looks to me you're trying to create some events/handlers?
Pretty much, I'm actually using boost::signals2 for the publishing (since I'm multithreading and this already has some built in support for that) as well as boost::asio for the thread pools.

I'm basically trying to figure out if I can get the "Topic" out of the "Subject" they are observing, without casting, at the same time make it so that their switches can be used intuitively using a combination of the conversion and function operator.

It might just be overkill...
Topic archived. No new replies allowed.