• Advertisement
Sign in to follow this  
  • entries
    73
  • comments
    131
  • views
    54868

I like templates

Sign in to follow this  

126 views

I finally buckled down and learned templates. More than the basic "class T" prefix to a class too, the real in-depth stuff. I realized that didn't really know them.

I've heard from people that hate them, and I've heard from people who love them. I love them, personally, though I'll admit they aren't perfect. Sure, they aren't true generics, but there is some advantage to that. It takes a while to learn them, but man, you can sure do some powerful stuff with it.

This templated function is the equivalent to explicit casting:

template <class T, class pT>
T convert(pT v) {
return (T)v;
}

baseClass *b;
derivedClass *d;
convert(d);




You wouldn't really need a function like that, but it's cool because you could add some stuff in the function like type checking if you wanted to simulate your own inheritance system or something. Could be useful for other things.

It's also pretty neat how C++ can deduce some template types; for example, the convert function could be called by:

convert(d);

And since the second template parameter is used as a formal parameter, it can deduce the type by the type of object passed in. So there you have your own converter, and you can do stuff within the function if you wanted.. I can see why templating would be nice for memory allocators.

Heck, is that how "static_cast" and "dynamic_cast" are built? Cool.

If I'm doing anything dangerous so far, please tell me. Or just any pointers about things I need to watch out for. I've heard that compiler support for advanced templating is wishy-washy (partial template specialization? haven't gotten there yet). I'm using VS .NET 2003, so I don't think there should be any problems.

--

Invalid and dangerous pointer casting

Edit: I made a thread about this because I really want to know the answer.

As an aside, I'm playing around with pointers and what can go wrong with them. I've been using C++ for a while, so I understand them fairly well. I'm trying to understand how classes are represented in memory though, and exactly what happens when you cast a pointer to an invalid type. For example:


class a {
public:
a() {}
virtual ~a() {}

const char* getName() { return "Hi! I'm a"; }
};

class c {
public:
c() { num = 5; }
virtual ~c() {}

int getNumber() { return num; }

private:
int num;
};

c* cInstance = new c;
printf("%s\n", ((a*)cInstance)->getName());





*Somehow* this correctly prints out "Hi! I'm a". How in the world is possible? I know that it's sometimes possible that memory happens to map out correctly and it seems like everything is ok, even though something very dangerous happened. But in this case, how is ever calling code that prints that out when we are dealing with an instantiated "c" class? I thought that it would try to execute memory that is part of the "c" class, who knows what memory, and it would probably crash. But how it ever calls code from class "a", especially when we never even instantiate an object of type "a", it beyond me. Can anyone help? As I said before, I'm using VS .NET 2003.
Sign in to follow this  


2 Comments


Recommended Comments

From there, you can make a boost::lexical_cast:


include <stringstream>

template <class TO, FROM>
TO Convert(FROM val){
std::sstream s;
TO ret;
s << val;
s >> ret;
return ret;
}


... If memory recalls correctly.

Share this comment


Link to comment
Methods of a class are, for simplicitys sake, stored exactly as normal functions but with a hidden 'this' parameter. The class then stores the address of this function and the compiler passes the necessary class instance for you. So using your example the compiler generates two functions.

int getNumber( c* instance );
const char* getName( a* instance );

And then each class gets a lookup table to its methods, so class a has in its lookup table:

MethodLUT-Pos-1: getName: 0xAABBCCDD;

class c has:

MethodLUT-Pos-1: getNumber: 0xBBAACCDD;

Now when you cast an instance of c to a the compiler then checks a's method LUT for the address of the function and finds getName. getName in this example doesnt actually reference any memory from the associated instance of a, only a constant, so no memory access violation occurs.

I hope thats clear, some of it has been over simplified to hopefully make the explanation a bit clearer.




Share this comment


Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement