Originally Posted by
medievalelks
I prefer the cleaner design over a perceived performance gain.
I agree, but the performance gain is not just perceived.
Elaborating on King Mir's example, if you wanted it to be legible, you would typedef the different choices, so it's cleaner. However, in that case you would just end up with this example.
Code:
#include <iostream>
#include <string>
class Car
{
public:
void ViewData()
{
std::cout << "<Car>" << std::endl;
}
};
class Motor {};
class Plane {};
class Handler
{
Car car;
Motor motor;
Plane plane;
public:
struct Type
{
template<int I>
class Mclass {};
typedef Mclass<0> car_type; //or u can use: class car_type {}
typedef Mclass<1> motor_type; //or u can use: class motor_type {}
typedef Mclass<2> plane_type; //or u can use: class plane_type {}
static const car_type Car;
static const motor_type Motor;
static const plane_type Plane;
};
Car& GetData(Type::car_type const& t)
{
return car;
}
Motor& GetData(Type::motor_type const& t)
{
return motor;
}
Plane& GetData(Type::plane_type const& t)
{
return plane;
}
};
const Handler::Type::car_type Handler::Type::Car = Handler::Type::car_type();
const Handler::Type::motor_type Handler::Type::Motor = Handler::Type::motor_type();
const Handler::Type::plane_type Handler::Type::Plane = Handler::Type::plane_type();
int main()
{
Handler handler;
handler.GetData(Handler::Type::Car).ViewData(); //output: <Car>
}
If you're going to do something illegible, or verbose, such as these examples, why don't you just do handler.GetCar().ViewData()? If you only have 1 instance of each class, as your first code shows, then the best solution would be to give them individual functions. If however you have multiple instances, then you would need an index based approach such as King Mir's, or medievalelks with an array:
Code:
#include <iostream>
#include <string>
#include <vector>
class Viewable
{
public:
virtual void ViewData() = 0;
};
class Car : public Viewable
{
public:
virtual void ViewData()
{
std::cout << "<Car>" << std::endl;
}
};
class Motor : public Viewable
{
public:
virtual void ViewData()
{
std::cout << "<Motor>" << std::endl;
}
};
class Plane : public Viewable
{
public:
virtual void ViewData()
{
std::cout << "<Plane>" << std::endl;
}
};
class Handler
{
std::vector<Viewable*> data;
public:
Viewable* GetData(int i)
{
return data[i];
}
void Add(Viewable* v)
{
data.push_back(v);
}
Viewable* operator[](int i)
{
return GetData(i);
}
};
int main()
{
Handler* handler = new Handler;
handler->Add(new Car);
handler->Add(new Motor);
handler->Add(new Plane);
handler->GetData(0)->ViewData(); //same as handler[0]->ViewData(); with non-pointer
}
Personally if I were handling multiple instances of multiple unknown classes, I would do something along the lines of this...
Code:
#include <iostream>
#include <string>
#include <vector>
#include <boost/any.hpp>
class Car
{
public:
void ViewData()
{
std::cout << "<Car>" << std::endl;
}
};
class Motor {};
class Plane {};
class Handler
{
std::vector<boost::any> data;
public:
template<typename T>
T GetData(int i)
{
return boost::any_cast<T>(data[i]);
}
template<typename T>
void Add(T v)
{
data.push_back(boost::any(v));
}
};
int main()
{
Handler handler;
handler.Add(Car());
handler.Add(Motor());
handler.Add(Plane());
handler.GetData<Car>(0).ViewData();
}
Unfortunately you have to cast the type, but C/C++ don't yet have a way of determining the type without help from the user (too bad we couldn't have an array of typedef's or something). Maybe C++0x, I don't know.
That just looks like a generic array now though. What the heck is the purpose? Game asset handler? If that's the case, you might want to implement Provider's, and instead of using int's (0, 1, 2, etc) to access them, give them string names (use an unordered_map). ie. handler.GetProvider<Car>().GetAsset("ferrari") or handler.GetAsset<Car>("ferrari") or handler.GetProvider("car").GetAsset("ferrari"), etc. There's more about that on gamedev.