fjanisze
fjanisze

Reputation: 1262

static casting from a base class to derived

There's something not clear to me i wish to put under your attention, please check those code snippets:

template< typename DerivedClass >
class construction_management
{
    city* this_city;
public:
    construction_management()
    {
        this_city = static_cast< city* >(this);
    }
    ~construction_management();
};

I removed intentionally all the not necessary code, please look at the constructor which make a static cast of the 'this' pointer to a type 'city', which is defined as below:

class city : public construction_management< city >
{

public:

public:
    city( const string& name, const string& owner );
};

The class is intentionally empty, since i think nothing it can contain is relevant here. Want i'm not able to understand at 100% is what is happening here, g++ 4.7.2 prints not warning or error during the compiling phase, and whenever i use the 'this_city' pointer i can access all the public members of city, the object itself looks consistent since all the variables are properly initialized and contain always valid data.

What i wish to know, is why this code does not work if i define construction_management as a plain non-template class? The cast fails due to a conversion tentative from const to non const pointer to city, why?

This is the error print:

game.hpp: In constructor 'city_manager::construction_management::construction_management()':
game.hpp:164:41: error: invalid static_cast from type 'city_manager::construction_management* const' to type 'city_manager::city*'

And why work if construction_management is a template? Is this a kind of CRTP?

Thank you all.

Upvotes: 1

Views: 2728

Answers (1)

Andrei Tita
Andrei Tita

Reputation: 1236

It's CRTP and it works because of lazy template instantiation.

The line:

this_city = static_cast< city* >(this);

Requires this to be convertible to a city*. That does work if city is derived from construction_management. However, base classes must have complete declarations before derived classes, so there is only one way to write that:

//template code may or may not be present
class construction_management {...};
//maybe more code here
class city: public construction_management {...};

If the base class is not a template, it is instanced when the compiler first sees the code. Then the compiler runs into the constructor, it doesn't know at that point that city is derived from construction_management (or even what a city is, if it hasn't been declared as an incomplete type), and gives up.

However, if the base class is a template, it is instanced when inheritance is declared (somewhere around that time anyway, I'm not an expert on this). At that point, the compiler knows that city is derived from construction_management<city>, and everything works.

For the same reasons, it also works without a template if you move the constructor definition to a file which is compiled later (most likely from the .h to the .cpp).

Upvotes: 5

Related Questions