LogRus, отчасти ты прав.
Тем не менее, приведу варианты на мой взгляд правильных решений:
b.a = a.a;
т.е. полный перечень всех присваиваемых полей. И не надо оправдываться ленью. Такое описание в коде при
прочтении этого кода не оставляет никаких недоразумений по поводу неиницализированных полей. Аналогично в случае вложенных структур.
Вариант с конструктором я приводил выше. Правильно написанный конструктор гарантирует, что все поля будут инициализированы (включая те, которые не заполняются из A). Это снимает с пользователя заботу о неинициализированных значениях переменных. Используется инкапсуляция.
struct B: public A
{
int b;
void loadFrom(const A &a)
{
(A &)(*this) = a;
}
}
Отдельный метод, который скрывает от пользователя особенности реализации копирования данных из A в B. Этот же метод может содержать код, контролирующий сохранение логической целостности данных и обработку полей, не входящих в A. Опять используется инкапсуляция, а за непродуманность реализации метода отвечает программист-разработчик этой идеи, а не программист-пользователь, который не узнал/не догадался, как нужно правильно записать. В этом же случае полезно делать закрытые поля и предоставлять доступ к ним через аксессоры.
Два последних подхода с точки зрения пользователя записываются в одну строчку, что обеспечивает повторное использование кода копирования по всей системе и одинаковость процесса копирования. При реализации стиле C нужно завести отдельную функцию копирования.