Все верно, нельзя приводиться снизу вверх, только сверху вниз. Это ради безопасности.
если мы приведем указатель сверху вниз, т.е. к родителю, после чего передадим указатель куда нить в другую область видимости, то там будут доступны поля потомка?
Комбинатор: Ренат, вы в курсе что такое dynamic_cast?
Конечно.
Вы посмотрите на обсуждаемый кусок кода MQL5. Создается экземпляр базовый, а потом героически пытается преобразоваться через динамик каст в потомка в нарушение системы безопасности. Ну и облом конечно.
В документации прямо этот же пример рассмотрен и объяснен. Динамический кастинг при исполнении срабатывает только после прохождения проверки системы безопасности и допустимости преобразований. У каждого объекта MQL5 есть вся мета-информация для проверки прав во время исполнения. Это не пустой С++.
Динамическое приведение типов с помощью оператора dynamic_cast
Существует возможность динамического приведения типов с помощью оператора dynamic_cast, который может быть применён только к указателям классов. При этом проверка корректности типов производится в момент выполнения программы. Это означает, что при использовании оператора dynamic_cast компилятор не производит проверку типа данных, используемого для приведения. В случае, если осуществляется преобразование указателя к типу данных, который не является фактическим типом объекта, результатом будет значение NULL.
dynamic_cast <type-id> ( expression )
Параметр type-id в угловых скобках должен быть указателем на ранее определённый тип класса. Тип операнда expression (в отличии от C++) может быть любым, кроме void.
Пример:
class CBar { }; class CFoo : public CBar { }; voidOnStart() { CBar bar; //--- динамическое приведение типа указателя *bar к указателю *foo разрешено CFoo *foo = dynamic_cast<CFoo *>(&bar); // критической ошибки выполнения не возникнет Print(foo); // foo=NULL //--- попытка явного приведения ссылки объекта типа Bar к объекту типа Foo запрещено foo=(CFoo *)&bar; // возникнет критическая ошибка выполнения Print(foo); // эта строка не будет выполнена }
Точно? Потому что dynamic_cast чаще всего как раз нужен для приведения снизу вверх, от родителя к потомку.
Мало того, в MQL он отлично приводит снизу вверх даже в том случае когда не должен:
class A
{
public:
virtualvoid f()
{
Print("1");
}
};
class B: public A
{
public:
virtualvoid f()
{
Print("2");
}
};
voidOnStart()
{
A* ptr1 = new B();
ptr1.f();
A* ptr2 = new A();
ptr2.f();
B* casted = dynamic_cast<B*>(ptr1);
casted.f();
B* casted1 = dynamic_cast<B*>(ptr2);
casted1.f(); // здесь должна быть ошибка потому что casted1 должен быть null
delete ptr1;
delete ptr2;
}
вывод:
2017.05.13 18:30:14.864 t ETHUSD,M5: 2
2017.05.13 18:30:14.865 t ETHUSD,M5: 1
2017.05.13 18:30:14.866 t ETHUSD,M5: 2
2017.05.13 18:30:14.867 t ETHUSD,M5: 2
Renat Fatkhullin:
Вы посмотрите на обсуждаемый кусок кода MQL5.
Да, он не должен работать, и выше уже объяснили почему, но совсем не потому что каст снизу вверх невозможен.
Konstantin: если мы приведем указатель сверху вниз, т.е. к родителю, после чего передадим указатель куда нить в другую область видимости, то там будут доступны поля потомка?
Сначала проверяем неразрешенный кастинг снизу вверх и получаем NULL. Все верно.
Потом создаем объект CLASS2, присваиваем ссылку на него родительскому классу (тут важно понять, что в динамике среда знает, что исконный тип объекта CLASS2 - это хранится в его метаинформации). Далее (как раз ваш вопрос) динамически кастим (с проверкой права преобразования на основе метаинформации исходного объекта) из ссылки CLASS1 в CLASS2.
Проверяем результат кастинга и прописываем в переменную i = 1. В финале выводим значение i, обращаясь к исходно созданному объекту.
Все работает верно и по спецификации (включая dynamic_cast спеку самого C++).
Все верно, нельзя приводиться снизу вверх, только сверху вниз.
В смысле нельзя приводить от базового класса к потомку?
Да, в случае когда на базовом не лежит реально сконструированный потомок.
Все верно, нельзя приводиться снизу вверх, только сверху вниз. Это ради безопасности.
Да.
Ренат, вы в курсе что такое dynamic_cast?
Конечно.
Вы посмотрите на обсуждаемый кусок кода MQL5. Создается экземпляр базовый, а потом героически пытается преобразоваться через динамик каст в потомка в нарушение системы безопасности. Ну и облом конечно.
В документации прямо этот же пример рассмотрен и объяснен. Динамический кастинг при исполнении срабатывает только после прохождения проверки системы безопасности и допустимости преобразований. У каждого объекта MQL5 есть вся мета-информация для проверки прав во время исполнения. Это не пустой С++.
Динамическое приведение типов с помощью оператора dynamic_cast
Существует возможность динамического приведения типов с помощью оператора dynamic_cast, который может быть применён только к указателям классов. При этом проверка корректности типов производится в момент выполнения программы. Это означает, что при использовании оператора dynamic_cast компилятор не производит проверку типа данных, используемого для приведения. В случае, если осуществляется преобразование указателя к типу данных, который не является фактическим типом объекта, результатом будет значение NULL.
dynamic_cast <type-id> ( expression )
Параметр type-id в угловых скобках должен быть указателем на ранее определённый тип класса. Тип операнда expression (в отличии от C++) может быть любым, кроме void.
Пример:
class CBar { };
class CFoo : public CBar { };
void OnStart()
{
CBar bar;
//--- динамическое приведение типа указателя *bar к указателю *foo разрешено
CFoo *foo = dynamic_cast<CFoo *>(&bar); // критической ошибки выполнения не возникнет
Print(foo); // foo=NULL
//--- попытка явного приведения ссылки объекта типа Bar к объекту типа Foo запрещено
foo=(CFoo *)&bar; // возникнет критическая ошибка выполнения
Print(foo); // эта строка не будет выполнена
}
Конечно.
Точно? Потому что dynamic_cast чаще всего как раз нужен для приведения снизу вверх, от родителя к потомку.
Мало того, в MQL он отлично приводит снизу вверх даже в том случае когда не должен:
Вы посмотрите на обсуждаемый кусок кода MQL5.
Да, он не должен работать, и выше уже объяснили почему, но совсем не потому что каст снизу вверх невозможен.
если мы приведем указатель сверху вниз, т.е. к родителю, после чего передадим указатель куда нить в другую область видимости, то там будут доступны поля потомка?
Да, вот пример, демонстрирующий ваш вопрос:
и вывод:Сначала проверяем неразрешенный кастинг снизу вверх и получаем NULL. Все верно.
Потом создаем объект CLASS2, присваиваем ссылку на него родительскому классу (тут важно понять, что в динамике среда знает, что исконный тип объекта CLASS2 - это хранится в его метаинформации). Далее (как раз ваш вопрос) динамически кастим (с проверкой права преобразования на основе метаинформации исходного объекта) из ссылки CLASS1 в CLASS2.
Проверяем результат кастинга и прописываем в переменную i = 1. В финале выводим значение i, обращаясь к исходно созданному объекту.
Все работает верно и по спецификации (включая dynamic_cast спеку самого C++).
Точно? Потому что dynamic_cast чаще всего как раз нужен для приведения снизу вверх, от родителя к потомку.
Мало того, в MQL он отлично приводит снизу вверх даже в том случае когда не должен:
Точно:
Не забывайте обновляться на последние билды. Я сейчас тестируюсь на 1598, который выкладывался недавно в виде зипов в этой ветке вроде.
Не забывайте обновляться на последние билды.
Да, старый билд.
Все верно, нельзя приводиться снизу вверх, только сверху вниз. Это ради безопасности.