My question, which is in the last paragraph, needs (in my opinion) some explanatory setup. Basically, I'm wondering if you can avoid using templates if instead you make all your would-be template classes instead inherit from a base class that declares virtual methods you will be using, among them a function for memory allocation that, when implemented, will return a pointer to the derived (not base) type.
BEGIN setup
C++ does not seem to have the notion of a "universal base class" from which everything is implicitly derived; I imagine that class would be defined like this:
class universal_base
{
};
Of course, now that I have defined it, I can make all my classes derive from it. Then, because of polymorphism, any references or pointers to universal_base
that I pass around will be basically the same as template parameters:
template <typename T>
class C
{
T &x;
int f(T &y);
C(T &z): x(z + 1) {}
};
class C
{
universal_base &x;
int f(universal_base &y);
C(universal_base &z): x(z + 1) {}
};
The difference is that in the first construction, the expression z + 1
can't be guaranteed to be valid; you just have to tell users that T
must overload operator+
. In the second construction, I could add a virtual such operator to universal_base
:
// in universal_base
public:
virtual universal_base& operator+(const universal_base &x) = 0;
and use typeid
and dynamic_cast
in the implementations to get the argument right. This way, it is impossible to write ill-formed code, because the compiler will complain if you don't implement operator+
.
Of course, this way it is not possible to declare members of non-reference type:
class C: public universal_base
{
universal_base x; // Error: universal_base is a virtual type
};
However, this can be gotten around through careful use of initialization. In fact, if I wanted to create a template for the above,
template <typename T>
class C: public universal_base
{
T x;
};
I would almost certainly be giving it objects of type T
at some point. In that case, there is no reason that I could not do the following:
class universal_base
{
public:
virtual universal_base& clone() = 0;
};
class C: public universal_base
{
universal_base &x;
C(universal_base &y) : x(y.clone()) {}
}
Effectively, I create a variable of a type that is determined at runtime. This of course requires that every object of type C
be appropriately initialized, but I do not think this is a huge sacrifice.
This is not academic, since it has the following use: if I am writing a module that is intended to be linked into other programs and handle their data in some generic way, I cannot possibly know the types that will be used. Templates are not helpful in this situation, but the technique above works fine.
END setup
So, my question: does this completely replace templates, modulo the thing about initialization? Is it inefficient or dangerous somehow?