На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела:
1. Название темы - краткое описание кто/что против кого/чего
2. В первом сообщении - список параметров, по которым идет сравнение.
3. Старайтесь аргументировать свои высказывания. Фразы типа "Венда/Слюникс - ацтой" считаются флудом.
4. Давайте жить дружно и не доводить обсуждение до маразма и личных оскорблений.
Модераторы: Модераторы, Комодераторы
Страницы: (2) [1] 2  все  ( Перейти к последнему сообщению )  
> Касты в статике и динамике , "больше" значит "лучше"?
    Для тех, кто не в теме, краткая выдержка. При необходимости скопировать базовый подобъект из одного экземпляра в другой (возможно, другого класса, но базовый подобъект того же), у ТС возникла проблема из-за ошибочного каста левого операнда operator= к rvalue вместо lvalue. Вопрос был решён во втором же посту. Исходный топик тут. Затем в тему пришёл yuriunknown, и понеслось.
      Dushevny во первых в классе А необходм оператор копирования и конструктор копирования, во вторых НЕ (a)B = C а (a)B = (a)C но в данном случае создатся два временных объекта (на базе С и на базе В), поэтому пользы мало
      Вбей данный код, сам всё поймёшь
      ExpandedWrap disabled
        #include <iostream>
        using namespace std;
         
        class a
        {
        protected:
            int A;
            public:
            a() : A(0) {
                cout<<"DC : A OBJ CREATED : "<<(size_t)(this)<<endl;
            }
            a(const a &_copy){
                cout<<"CC : A OBJ CREATED : "<<(size_t)(this)<<endl;
                A = _copy.A;
            }
            a & operator =(const a &_copy){
                A = _copy.A;
                return *this;
            }
            int data() const {
                return A;
            }
        };
         
        class b: public a
        {
        protected:
            int B;
            public:
            b() : B(1) { a::A = B; }
        };
         
        class c: public a
        {
        protected:
            int C;
            public:
            c() : C(2) { a::A = C; }
        };
         
        int main(){
            b B;
            c C;
            (a)B = (a)C;
            cout<<B.data()<<endl;
            return 0;
        }

      Чтобы заработало как надо либо снабди интерфейсы классов необходимыми операторами копирования, либо используй вариант
      ExpandedWrap disabled
        ((a *)&B)[0] = (a)C;
      - так заработает, но это будет крайне нерационально т.к будешь плодить временные объекты(это глупо)
      Моя рекомендация использовать virtual наследование и dynamic_cast с разыменовыванием указателей
      ExpandedWrap disabled
        #include <iostream>
        using namespace std;
         
        class a
        {
        protected:
            int A;
            public:
            a() : A(0) {
                cout<<"DC : A OBJ CREATED : "<<(size_t)(this)<<endl;
            }
            a(const a &_copy){
                cout<<"CC : A OBJ CREATED : "<<(size_t)(this)<<endl;
                A = _copy.A;
            }
            a & operator =(const a &_copy){
                A = _copy.A;
                return *this;
            }
            int data() const {
                return A;
            }
            virtual ~a(){}
        };
         
        class b: public a
        {
        protected:
            int B;
            public:
            b() : B(1) { a::A = B; }
        };
         
        class c: public a
        {
        protected:
            int C;
            public:
            c() : C(2) { a::A = C; }
        };
         
        int main(){
            b B;
            c C;
            a * ptrB = dynamic_cast<a *>(&B);
            a * ptrC = dynamic_cast<a *>(&C);
            if( ptrB &&ptrC )
                *ptrB = *ptrC;
            cout<<B.data()<<endl;
            return 0;
        }


      Добавлено
      static_cast, не рекомендую так как не будет чеков в рантайме, а это как показывает практика приводит к ошибкам кастования.

      Это сообщение было перенесено сюда или объединено из темы "приведение lvalue к типу предка работает не так, как я ожидаю"
      Сообщение отредактировано: yuriunknown -
        yuriunknown, заранее извиняюсь, кто тебя языку учил?

        Это сообщение было перенесено сюда или объединено из темы "приведение lvalue к типу предка работает не так, как я ожидаю"
          Qraizer, что именно подразумеваешь своим вопросом?И касательно какого языка, (разговорного или алгоритмического) возникли вопросы?

          Это сообщение было перенесено сюда или объединено из темы "приведение lvalue к типу предка работает не так, как я ожидаю"
          Сообщение отредактировано: yuriunknown -
            yuriunknown, Для каста указателя или ссылки к указателю/ссылке на базовый класс нет смысла использовать dinamic_cast. Он всё равно заменяется на static_cast самим компилятором.
            dinamic_cast предназначен для проверки на объект какого именно производного класса ссылается указатель базового и для соответствующего преобразования указателя.

            Это сообщение было перенесено сюда или объединено из темы "приведение lvalue к типу предка работает не так, как я ожидаю"
              amk слушай я не имею ничего против тебя только не учи меня букварю, ладно?
              ExpandedWrap disabled
                #include <iostream>
                using namespace std;
                 
                class a {
                protected:
                    size_t A;
                    public :
                    a()   : A(0){}
                    virtual ~a(){}
                };
                 
                class b : public a{
                protected:
                    size_t B;
                    public:
                    b()   : B(1){}
                };
                 
                int main(){
                    a *arr[] = {0, 0};
                    arr[0] = new a();
                    arr[1] = new b();
                    b * ptr1 = static_cast < b *>(arr[0]);
                    b * ptr2 = dynamic_cast< b *>(arr[1]);
                    b * ptr3 = dynamic_cast< b *>(arr[0]);
                    cout<<hex<<ptr1<<endl;
                    cout<<hex<<ptr2<<endl;
                    cout<<hex<<ptr3<<endl;
                    return 0;
                }

              http://codepad.org/su1MMDtA

              Добавлено
              static_cast - в неумелых руках - ЗЛО в первом лице. Тоже касается cons_cast - а, dynamic_cast позволяет 100% знать какой виртуальный потомок из дерева наследования в данный момент в программе. Я закончил.
              Адишн : Он всё равно заменяется на static_cast самим компилятором. - не пиши так больше.

              Сообщения были разделены в тему "Касты в статикее и динамике"

              Это сообщение было перенесено сюда или объединено из темы "приведение lvalue к типу предка работает не так, как я ожидаю"
              Сообщение отредактировано: yuriunknown -
                Я же извинился, да? Ну да, точно.
                Цитата yuriunknown @
                И касательно какого языка, (разговорного или алгоритмического) возникли вопросы?
                Тут раздел по С++. Впрочем, неуважение к русскому тоже не приветствуется.
                Первый приведённый код вообще о чём был? Если о том, что уже разъяснено в сообщении №2, то он слегка припоздал. А если о том, что требуется приведение типа для правого операнда, то он демонстрирует только избыточность как самого каста, так и перегрузки operator=(). И никаких временных объектов.
                Цитата yuriunknown @
                Моя рекомендация использовать virtual наследование и dynamic_cast с разыменовыванием указателей
                Интересно, как же тогда в C копировали структуры обычным присваиванием, если для этого нужно обязательно виртуальный базовый класс и проверки типов в run-time. Кстати, что-то я не вижу во втором приведённом коде виртуальных базовых классов.
                Цитата yuriunknown @
                static_cast, не рекомендую так как не будет чеков в рантайме, а это как показывает практика приводит к ошибкам кастования.
                Если в run-time не будет избыточных действий, программа от этого только выиграет. Ошибки кастов при восходящем приведении типов могут быть только, если обманывать компилятор.

                Добавлено
                Цитата yuriunknown @
                amk слушай я не имею ничего против тебя только не учи меня букварю, ладно?
                В букваре написано, что любой указатель или ссылка на производный класс может быть приведён к указателю или соответственно ссылке на доступный однозначный базовый класс. Цитировать Стандарт надо? Как-никак, не букварь, однако.

                Добавлено
                Цитата yuriunknown @
                Помимо этого в букваре также должно быть разъяснено, чем отличается нисходящий каст от восходящего, а также перекрёстного.

                Эта тема была разделена из темы "приведение lvalue к типу предка работает не так, как я ожидаю"
                  Qraizer я немного не понял может мне уйти с этого ресурса?Как я вижу, кроме культа личности(не будем показывать на аватр выше) тут не дорожат участниками.
                  Можно было прямо написать или нет?Ну так скажи я пошлю и этот форум. Поясни мне глупому твой до*б.
                  ЗЫ: А может тебе не даёт покоя мой АйПишник, верней откуда он, ну так напиши конкретно(можешь в ЛС) что это за почести от тебя в мою сторону пошли?


                  Добавлено
                  Цитата
                  Интересно, как же тогда в C копировали структуры обычным присваиванием, если для этого нужно обязательно виртуальный базовый класс и проверки типов в run-time. Кстати, что-то я не вижу во втором приведённом коде виртуальных базовых классов.
                  - ну так увидь, плохо значит смотришь. На счёт Си - давай не будем мешать процедурный и объектно ориентированный язык, ладно?
                  Сообщение отредактировано: yuriunknown -
                    yuriunknown, Qraizer просто указывает на допущенные тобой неточности. А он здесь, пожалуй один из десятка (даже меньше), кто реально знает стандарт языка. Ну или почти знает. Мне по крайней мере до него далеко. Так что к его мнению в этом вопросе лучше прислушаться, а не вступать в бессмысленный спор.
                    Цитата yuriunknown @
                    ЗЫ: Чисто для себя - причём к объектно ориентированному языку процедурный?(Тут речь шла о плюсах)
                    Тут речь шла не столько о плюсах, сколько об реализации протокола обмена. То есть топикстартеру требуется получить не объект с неважно какими внутренностями, а вполне определённую последовательность байт (если не бит). В таких случаях волей-неволей приходится откатываться к использованию средств, пришедших в язык из его предка. И классы с виртуальным наследованием здесь вообще не катят, поскольку их внутренней структурой нельзя управлять простыми средствами.
                      amk
                      Цитата
                      о есть топикстартеру требуется получить не объект с неважно какими внутренностями, а вполне определённую последовательность байт (если не бит).
                      - где сие было упомянуто?
                        yuriunknown, поступай, как будет угодно. Участникам на этом ресурсе всегда рады, когда они создают полезный контент. Хотя бы капельку полезный. Я не виноват, что ты уже второй раз заходишь в чью-то уже решённую тему и устраиваешь балаган из наполовину очевидных, наполовину ложных тезисов. Вопрос Dushevny-а создал полезного контента больше. Третий раз увидеть балаган в ещё одной теме я не хочу, это правда.

                        Добавлено
                        Если не согласен с критикой, потрудись объяснить поведение кода по ссылке из моего поста выше. Результат там противоречит твоим утверждениям. Твои утверждения касательно static_cast<> не согласуются с гарантиями Стандарта языка. Цитаты могу привести. Твои примеры, якобы подтверждающие твою правоту касательно dynamic_cast<>, относятся к совершенно другой предметной области, не рассматриваемой в этой теме. В конце концов ты первый оскорбил amk, который, судя по твоим постам, язык знает куда лучше тебя.

                        Добавлено
                        Цитата yuriunknown @
                        Цитата
                        ...Кстати, что-то я не вижу во втором приведённом коде виртуальных базовых классов.
                        - ну так увидь, плохо значит смотришь.
                        Я один плохо смотрю, или ещё есть? Вопрос не напотроллить, ибо наличие виртуальных баз как раз может служить причиной, почему вместо static_cast<> в восходящем касте может потребоваться dynamic_cast<>. А может и не потребоваться. Но может потребоваться. так что вопрос важный. Кто-нибудь вообще, кроме yuriunknown, видит там хоть один виртуальный базовый класс?
                          Qraizer а что мне пояснять, ты сделал проверку компилятором ещё на этапе сборки и зашил в код(я рад за тебя, чуть выше я показал что такой подход может привести к ошибке кастования), далее, если внимательно почитаешь сам топик, то увидишь что написал автор темы
                          Цитата
                          Варианты *(a*)&B = C и *static_cast<a*>(&B) = C; генерят необходимый код, но мне не понятно, чем они отличаются от (a)B = C и почему код (a)B = C выкидывается компилятором?
                          - т.е твой код уже повтороение того, что и так было известно автору, он просил пояснения по поводу брыка от компилятора на (a)B = C, ну и дальше по теме автор ничего указанногго тобой так и не одобрил. Я решил предложить свой вариант, который будет гарантированно работать. Не любишь динамик каст - твои проблемы, а я статик каст не люблю.
                          Касательно избыточности, т.е конструктор преобразования по твоёму не избыточен, а вот оператор копирования избыточен(NICE) :D На досуге почитай, что ли того же Пратту, там в самом начале есть что должно быть в интерфейсе класса, как раз некашерный для тебя оператор копирования делать рекомендовано.

                          НО раз тут разговор зашёл об избыточности кода то ок, я использую дефолт (для интерфейса базового класса в шапке темы он вполне уместен, кстати для варианта со структурой тоже)
                          http://codepad.org/ePQFTVXA и что, у кого теперь больше крючков в коде и чей код избыточен?

                          Qraizer слющаааай, а как ты будешь поступать если в базовом классе будет довольно много полей вместо одного int a(вот давай введём штук 16-ть разнородных полей простых типов - там вперемешку int float double), мне вот интересно : ну понятно мой код с динамик кастом сработает, а что будешь деать ты, будь добр дай ответ "гулпому падавану" в моём лице
                          Сообщение отредактировано: yuriunknown -
                            Ок, yuriunknown. Поехали по-серьёзному.
                            Приступим. dynamic_cast<>.
                            Цитата 5.2.7 Dynamic cast
                            1. The result of the expression dynamic_cast<T>(v) is the result of converting the expression v to type T. T shall be a pointer or reference to a complete class type, or “pointer to cv void.” The dynamic_cast operator shall not cast away constness (5.2.11).
                            2. If T is a pointer type, v shall be a prvalue of a pointer to complete class type, and the result is a prvalue of type T. If T is an lvalue reference type, v shall be an lvalue of a complete class type, and the result is an lvalue of the type referred to by T. If T is an rvalue reference type, v shall be an expression having a complete class type, and the result is an xvalue of the type referred to by T.
                            Это база. Если нарушаются эти пункты, компилятор регистрирует семантическую ошибку. Далее.
                            Цитата 5.2.7 Dynamic cast
                            3. If the type of v is the same as T, or it is the same as T except that the class object type in T is more cv-qualified than the class object type in v, the result is v (converted if necessary).
                            4 If the value of v is a null pointer value in the pointer case, the result is the null pointer value of type T.
                            Тривиальные случаи. При касте с устрожением квалификации квалификация добавляется, но в любом случае результат ссылается на исходный операнд. Каст пустого указателя оставляет результат пустым.
                            Цитата 5.2.7 Dynamic cast
                            5 If T is “pointer to cv1 B” and v has type “pointer to cv2 D” such that B is a base class of D, the result is a pointer to the unique B subobject of the D object pointed to by v. Similarly, if T is “reference to cv1 B” and v has type cv2 D such that B is a base class of D, the result is the unique B subobject of the D object referred to by v. 65 The result is an lvalue if T is an lvalue reference, or an xvalue if T is an rvalue reference. In both the pointer and reference cases, the program is ill-formed if cv2 has greater cv-qualification than cv1 or if B is an inaccessible or ambiguous base class of D. ... тут ещё пример

                            65) The most derived object (1.8) pointed or referred to by v can contain other B objects as base classes, but these are ignored.
                            Наиболее интересный случай. Каст к базе, в случае если база единственна и доступна, операнд приводится к целевому типу. В случае неоднозначности или недоступности компилятор регистрирует грамматическую ошибку. В случае отсутствия целевой базы у операнда, пункт не применяется.
                            Цитата 5.2.7 Dynamic cast
                            6. Otherwise, v shall be a pointer to or an lvalue of a polymorphic type (10.3).
                            Оппа. Только теперь Стандарт требует полиморфности операнда. Интересно. Но идём дальше.
                            Цитата 5.2.7 Dynamic cast
                            7 If T is “pointer to cv void,” then the result is a pointer to the most derived object pointed to by v. Otherwise, a run-time check is applied to see if the object pointed or referred to by v can be converted to the type pointed or referred to by T.
                            Совсем занимательно. Только сейчас программе требуется определение самого производного объекта, и если целью не является указатель на ничто, то дополнительно ещё и некие run-time проверки. "Внезапно" © выясняется, что до этого run-time проверок не требовалось.
                            Цитата 5.2.7 Dynamic cast
                            8. If C is the class type to which T points or refers, the run-time check logically executes as follows:
                            • If, in the most derived object pointed (referred) to by v, v points (refers) to a public base class subobject of a C object, and if only one object of type C is derived from the subobject pointed (referred) to by v the result points (refers) to that C object.
                            • Otherwise, if v points (refers) to a public base class subobject of the most derived object, and the type of the most derived object has a base class, of type C, that is unambiguous and public, the result points (refers) to the C subobject of the most derived object.
                            • Otherwise, the run-time check fails.
                            Первый элемент списка описывает нисходящие приведения, второй – перекрёстные. А третий запрещает остальные случаи. Как? А вот так:
                            Цитата 5.2.7 Dynamic cast
                            9. The value of a failed cast to pointer type is the null pointer value of the required result type. A failed cast to reference type throws std::bad_cast (18.7.2).
                            Ожидаемо, не правда ли? Именно так описывают dynamic_cast<> в букварях. Правда, там не всегда пишут, что делает dynamic_cast<> при восходящих и тривиальных кастах. А оказывается, что Стандарт описывает в таких случаях самые обычные статичные проверки, выполняемые компилятором. Который если при компиляции не обнаружит нарушений, в принципе неспособен сфэйлить каст. Нет, он, конечно, имеет полное право выполнить подобный каст в run-time, если дурак, но фэйлов не будет, раз уж компиляция прошла успешно.

                            Продолжение следует.
                            Сообщение отредактировано: Qraizer -
                              Ух... Как толсто то! Я то думал, что ЙА-шки только на фикбуке водятся, а оно вона как!

                              Добавлено
                              Цитата yuriunknown @
                              На досуге почитай, что ли того же Пратту

                              Я бы предложил вам почитать что-нибудь более основательное и авторитетное. Если Страуструп слишком объёмен и сложен, то Саттер с его "сложными задачами" - самое оно. Детально разжевывает предмет дискуссии. Ну, ещё можно погуглить на предмет Rule of Zero, Rule of Five, Rule of Three. Мне вот гугл первой же ссылкой выдал нужную страницу с cppreference.com.

                              Добавлено
                              Цитата yuriunknown @
                              Qraizer слющаааай, а как ты будешь поступать если в базовом классе будет довольно много полей вместо одного int a(вот давай введём штук 16-ть разнородных полей простых типов - там вперемешку int float double), мне вот интересно : ну понятно мой код с динамик кастом сработает, а что будешь деать ты, будь добр дай ответ "гулпому падавану" в моём лице

                              Я думаю, что Qraizer применит Rule Of Zero, и по барабану, сколько там полей в базовом/базовых классах.
                                Не уверен как в том, что тут есть о чем холиварить, так и в том, что виновник торжества будет здесь отвечать.
                                  Продолжение.

                                  static_cast<>.
                                  Цитата 5.2.9 Static cast
                                  1. The result of the expression static_cast<T>(v) is the result of converting the expression v to type T. If T is an lvalue reference type or an rvalue reference to function type, the result is an lvalue; if T is an rvalue reference to object type, the result is an xvalue; otherwise, the result is a prvalue. The static_cast operator shall not cast away constness (5.2.11).
                                  И снова база. Неинтересно, но познавательно.
                                  Цитата 5.2.9 Static cast
                                  2. An lvalue of type “cv1 B,” where B is a class type, can be cast to type “reference to cv2 D,” where D is a class derived (Clause 10) from B, if a valid standard conversion from “pointer to D” to “pointer to B” exists (4.10), cv2 is the same cv-qualification as, or greater cv-qualification than, cv1, and B is neither a virtual base class of D nor a base class of a virtual base class of D. The result has type “cv2 D.” An xvalue of type “cv1 B” may be cast to type “rvalue reference to cv2 D” with the same constraints as for an lvalue of type “cv1 B.” If the object of type “cv1 B” is actually a subobject of an object of type D, the result refers to the enclosing object of type D. Otherwise, the result of the cast is undefined.
                                  Описывается нисходящее приведение ссылок. Которое оказывается полностью допустимым, а результат соответственно правильным, если целевой потомок действительно включает исходный базовый подообъект. Однако в случае нарушения этого правила получаем неопределённое поведение вместо фэйла. И кроме того, таким образом нельзя выполнить каст из виртуальной базы целевого потомка, т.к. пункт не применяется.
                                  Цитата 5.2.9 Static cast
                                  3. A glvalue of type “cv1 T1” can be cast to type “rvalue reference to cv2 T2” if “cv2 T2” is reference-compatible with “cv1 T1” (8.5.3). The result refers to the object or the specified base class subobject thereof. If T2 is an inaccessible (Clause 11) or ambiguous (10.2) base class of T1, a program that necessitates such a cast is ill-formed.
                                  Восходящий каст ссылок. На всякий случай посмотрим сюда:
                                  Цитата 8.5.3 References
                                  4. Given types “cv1 T1” and “cv2 T2,” “cv1 T1” is reference-related to “cv2 T2” if T1 is the same type as T2, or T1 is a base class of T2. “cv1 T1” is reference-compatible with “cv2 T2” if T1 is reference-related to T2 and cv1 is the same cv-qualification as, or greater cv-qualification than, cv2. ...
                                  чтобы убедиться, что при восходящем приведении правила для ссылок в целом не отличаются от правил для указателей, до которых мы со временем дойдём.
                                  Цитата 5.2.9 Static cast
                                  4. Otherwise, an expression e can be explicitly converted to a type T using a static_cast of the form static_cast<T>(e) if the declaration T t(e); is well-formed, for some invented temporary variable t (8.5). The effect of such an explicit conversion is the same as performing the declaration and initialization and then using the temporary variable as the result of the conversion. The expression e is used as a glvalue if and only if the initialization uses it as a glvalue.
                                  Если исходным и целевым типом являются указатели, то применимость пункта зависит от применимости 8.5 Initializers к этой паре типов. Смотреть? Ну конечно смотреть. Смотрим.
                                  Цитата 8.5 Initializers
                                  1. A declarator can specify an initial value for the identifier being declared. The identifier designates a variable being initialized. The process of initialization described in the remainder of 8.5 applies also to initializations specified by other syntactic contexts, such as the initialization of function parameters with argument expressions (5.2.2) or the initialization of return values (6.6.3).
                                    initializer:
                                      brace-or-equal-initializer
                                      ( expression-list )

                                  ... тут остальные варианты, не имеющие отношения к рассматриваемому случаю
                                  Выделенный вариант как раз тот, который упоминается в вышеуказанном пункте static_cast<>.
                                  Цитата 8.5 Initializers
                                  2. Except for objects declared with the constexpr specifier, for which see 7.1.5, an initializer in the definition of a variable can consist of arbitrary expressions involving literals and previously declared variables and functions, regardless of the variable’s storage duration.
                                  Ну что ж, constexpr в вышеуказанном пункте static_cast<> отсутствует, посему продолжаем. Далее следуют определения терминов. Неинтересно в рассматриваемом контексте, так же как неинтересны и пункты, не относящиеся к указателям или имеющим пустой expression-list. Так что продолжим с
                                  Цитата 8.5 Initializers
                                  15. The initialization that occurs in the forms
                                    T x(a);
                                    T x{a};

                                  as well as in new expressions (5.3.4), static_cast expressions (5.2.9), functional notation type conversions (5.2.3), and base and member initializers (12.6.2) is called direct-initialization.
                                  Первый случай как раз наш.
                                  Цитата 8.5 Initializers
                                  16. The semantics of initializers are as follows. The destination type is the type of the object or reference being initialized and the source type is the type of the initializer expression. ... не наш случай.
                                  • If the initializer is a braced-init-list... не наш случай.
                                  • If the destination type is a reference type... не наш случай.
                                  • If the destination type is an array of characters, an array of char16_t, an array of char32_t, or an array of wchar_t, and... не наш случай.
                                  • If the initializer is ()... не наш случай.
                                  • Otherwise, if the destination type is an array... не наш случай.
                                  • If the destination type is a (possibly cv-qualified) class type:
                                    ... не наш случай.
                                  • Otherwise, if the source type is a (possibly cv-qualified) class type... не наш случай.
                                  • Otherwise, the initial value of the object being initialized is the (possibly converted) value of the initializer expression. Standard conversions (Clause 4) will be used, if necessary, to convert the initializer expression to the cv-unqualified version of the destination type; no user-defined conversions are considered. If the conversion cannot be done, the initialization is ill-formed. ... примечание о независимости квалификаторов и пример неинтересны.
                                  Ну наконец-то. Итак, следует посмотреть в ещё один пункт. Вот он
                                  Цитата 4.10 Pointer conversions
                                  3. A prvalue of type “pointer to cv D”, where D is a class type, can be converted to a prvalue of type “pointer to cv B”, where B is a base class (Clause 10) of D. If B is an inaccessible (Clause 11) or ambiguous (10.2) base class of D, a program that necessitates this conversion is ill-formed. The result of the conversion is a pointer to the base class subobject of the derived class object. The null pointer value is converted to the null pointer value of the destination type.
                                  Предыдущие два пункта не относятся к нашему случаю. В итоге имеем, что безусловно позволяется инициализировать типы указателей значениями их собственных типов, а также использовать значения указателей на производные классы для инициализации указателей на базовые при условии доступности и однозначности последних. Ну и в окончательном итоге получаем, что вышеуказанный пункт static_cast<> применим при касте указателей на производные классы в указатели на доступные однозначные базовые.

                                  Продолжение следует.
                                  Сообщение отредактировано: Qraizer -
                                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                  0 пользователей:


                                  Рейтинг@Mail.ru
                                  [ Script execution time: 0,1761 ]   [ 18 queries used ]   [ Generated: 29.03.24, 02:18 GMT ]