статическое приведение от базового класса к производному

Мне что-то непонятно, я хочу обратить ваше внимание, пожалуйста, проверьте эти фрагменты кода:

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

Я намеренно удалил весь ненужный код, посмотрите на конструктор, который делает статическое приведение указателя this к типу city, который определяется, как показано ниже:

class city : public construction_management< city >
{

public:

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

Класс намеренно пуст, так как я думаю, что ничего из того, что он может содержать, здесь не имеет значения. Хочу, чтобы я не мог на 100% понять, что здесь происходит, g++ 4.7.2 не выводит предупреждение или ошибку на этапе компиляции, и всякий раз, когда я использую указатель this_city, я могу получить доступ ко всем публичным членам города, сам объект выглядит согласованным, поскольку все переменные правильно инициализированы и всегда содержат действительные данные.

Что я хочу знать, так это то, почему этот код не работает, если я определяю Construction_management как простой нешаблонный класс? Приведение не выполняется из-за предварительного преобразования из константного в неконстантный указатель на город, почему?

Это печать ошибки:

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*'

А зачем работать, если Construction_management — это шаблон? Это типа CRTP?

Спасибо вам всем.


person fjanisze    schedule 03.01.2013    source источник
comment
Я бы сказал, что это это CRTP. Вы создаете экземпляр шаблона производного класса с его собственной базой. Насколько я знаю, это CRTP.   -  person Tony The Lion    schedule 03.01.2013


Ответы (1)


Это CRTP, и он работает из-за ленивой реализации шаблона.

Линия:

this_city = static_cast< city* >(this);

Требуется, чтобы this можно было конвертировать в city*. Это работает, если city происходит от construction_management. Однако базовые классы должны иметь полные объявления перед производными классами, поэтому есть только один способ написать это:

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

Если базовый класс не является шаблоном, он создается, когда компилятор впервые видит код. Затем компилятор запускает конструктор, он не знает, что city является производным от construction_management (или даже что такое city, если он не был объявлен как неполный тип), и сдается.

Однако, если базовый класс является шаблоном, он создается при объявлении наследования (во всяком случае, где-то в это время, я не эксперт в этом). В этот момент компилятор знает, что city является производным от construction_management<city>, и все работает.

По тем же причинам он также работает без шаблона, если вы переместите определение конструктора в файл, который компилируется позже (скорее всего, из .h в .cpp).

person Andrei Tita    schedule 03.01.2013
comment
Хм, работает нормально, если я поставлю конструктор кода в cpp. Моя единственная проблема сейчас связана с тем, как выглядит такой код с точки зрения дизайна и элегантности. Мне нужно получить доступ к некоторым элементам в городе, которым не разрешено присутствовать в качестве членов в Construction_management, например, структура player_info инкапсулирована в city, но Construction_management также нуждается в некоторой информации, содержащейся в этой структуре (а также другой класс, от которого наследуется город), поэтому я использую указатель this_city в базовом классе. - person fjanisze; 03.01.2013
comment
Довольно стандартно размещать код в файлах .cpp, тем более, что в противном случае он не будет работать. Единственный случай, когда вы вообще не должны этого делать, — это при написании шаблонов (именно поэтому код конструктора был в заголовочном файле в исходной, шаблонной версии вашего кода). - person Andrei Tita; 03.01.2013
comment
Я думал об использовании указателя this_city и этого приведения, должен ли я посмотреть на другое решение, по вашему мнению, или оно не так плохо, как я думаю? (я не знаю почему, но я как-то стараюсь избегать операций приведения). - person fjanisze; 03.01.2013
comment
@user1882090 user1882090 На ваше усмотрение. Некоторые люди предпочитают избегать такого дизайна. Мне вообще все равно, иногда так удобнее (этот случай?), а иногда просто приходится это делать. - person Andrei Tita; 03.01.2013