На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> приведение lvalue к типу предка работает не так, как я ожидаю , точнее, не работает
    Имеем два класса "b" и "c", оба наследники "a" и, соответственно, два объекта "B" и "C" этих классов.
    ExpandedWrap disabled
      class a
      {
          int A;
      };
       
      class b: public a
      {
          int B;
      };
       
      class c: public a
      {
          int C;
      };
       
      b B;
      c C;

    Я хочу скопировать "а"-часть из объекта "С" в объект "B".
    Варианты (a)B = C и static_cast<a>(B) = C компилятся без ошибок, но не гегенрят ни одной команды кода.
    Варианты *(a*)&B = C и *static_cast<a*>(&B) = C; генерят необходимый код, но мне не понятно, чем они отличаются от (a)B = C и почему код (a)B = C выкидывается компилятором?
      Цитата Dushevny @
      компилятся без ошибок, но не гегенрят ни одной команды кода.

      Скорее всего просто оптимизация.

      static_cast<a>(B) = C - создает временный объект типа a, скопированный из B, у временного объекта вызывается operator=(const A&), после чего объект сразу же уничтожается, не создавая никаких сайд-эфектов. Так как оператор у тебя тривиальный, то компилятор, наверно, считает, что это код ни на что не влияет и выкидывает его. Возможно (я плохо разбираюсь в оптимизациях которые делает компилятор), если ты определишь свой operator=, то код выбрасываться не будет, но в B нужного значения все равно не будет.

      делай так static_cast<a&>(B) = C;
        Да, похоже вы правы. Спасибо, с приведением к ссылке заработало.
          Всё правильно. Приведение к значению создаёт rvalue. Нужно приведение к ссылке, тогда будет lvalue.
            Но вообще, такое приведение в программе выглядит несколько неряшливо.
            Не лучше ли определить для классов b и c оператор присваивания, принимающий объект класса a и изменяющий нужную часть? Хотя бы посредством того же
            *static_cast<a *>this = a_value;
              Да, согласен. Но у меня это не классы, а структуры, описывающие протокол обмена. И в них операторы смотрятся еще более неуместными, как мне кажется, поскольку являются частью реализации одной конкретной части системы из всех.
                Тогда тем более непонятно использование для них слова class и наследования.
                Правильнее, проще и понятнее было бы назвать эти структeры struct a, struct b, struct c, включить struct a в остальные в качестве первого члена и не извращаться с преобразованием типов ссылок/указателей.
                  Цитата amk @
                  включить struct a в остальные в качестве первого члена и не извращаться
                  в данном случае включение противоречит концепции. Между а и b, a и c отношение "является" (is-a), а не "содержит" (has-a). И поскольку уровней наследования у меня сильно больше двух и они могут расти по мере добавления в протокол новых возможностей, а каждый родитель является, по сути, заголовком пакета для потомка - все это выливается в E.Header.Header.Header.Field_a, что совсем не способствует читаемости исходника.
                    Хозяин - барин. Можно подумать, static_cast<a&>(B) = C; делает код более удобочитаемым. Впрочем, наверно, эти действия спрятаны внутри функций.

                    Классы, вообще говоря, не предназначены для такого использования.
                      А струкуры? ;)
                        Ещё вариант.

                        ExpandedWrap disabled
                          #include <iostream>
                          using namespace std;
                           
                          struct A
                          {
                              int a;
                          };
                           
                          struct B : public A
                          {
                              int b;
                          };
                           
                          struct C : public A
                          {
                              int c;  
                          };
                           
                          int main() {
                              B b;
                              b.a = 2;
                              b.b = 3;
                              C c;
                              c.a = 4;
                              c.c = 5;
                           
                              std::cout << "1. B: {" << b.a << ", " << b.b << "}\n";
                              std::cout << "1. C: {" << c.a << ", " << c.c << "}\n";
                           
                              b.A::operator =(c);
                           
                              std::cout << "2. B: {" << b.a << ", " << b.b << "}\n";
                              std::cout << "2. C: {" << c.a << ", " << c.c << "}\n";
                           
                              return 0;
                          }
                        Сообщение отредактировано: Flex Ferrum -
                          Предположу, что у автора семейство типов struct sockaddr. Не спорю, там такой бардак развели...
                            Цитата Qraizer @
                            Предположу, что у автора семейство типов struct sockaddr. Не спорю, там такой бардак развели...

                            Ну, не совсем чтоб бардак - там что-то типа "распределённого union" :D
                            Но в целом согласен, всякий раз, когда делаю все эти танцы вокруг sockaddr/sockaddr_in/sockaddr_in6, хочется вымыть руки :lol:
                            0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                            0 пользователей:


                            Рейтинг@Mail.ru
                            [ Script execution time: 0,0316 ]   [ 16 queries used ]   [ Generated: 28.04.24, 03:19 GMT ]