LINUX.ORG.RU

Копирование дочернего класса в базовый - C++

 , , ,


0

2

Доброго времени суток. Меня интересует вопрос. Имеется вот такой код:

#include <iostream>

using namespace std;

class A
{
public:
    int a;
};

class B : public A
{
public:
    int b;
};


int main()
{
    A a;
    B b;
    a = b;
    //b = a;
    return 0;
}

Почему этот код работает? Какая логика у компилятора, когда он делает такое присваивание? Кто может обьяснить.

Правильно ли я рассуждаю: он видит присваивание обьекта дочернего класса обьекту базового класса. Он просто копирует все совпадающие поля. А остальные он не трогает. А копирует он так : он сам оператор присваивания для базового класса, и с помощью него присваивает. Элементы дочернего класса он не трогает, так как некуда их присваивать.

Может я где что забыл. Обьясните, пожалуйста.

P.S. А почему не работает код b = a ? ругается на неопределенный operator=. Хотя, по сути, что мешает присвоить дочернему классу базовый? ведь поля совпадают и он тоже может всё красиво сделать. ЧЯДНТ?

Какая логика у компилятора, когда он делает такое присваивание? Кто может обьяснить.

У класса A есть дефолтный конструктор копирования и operator=. Они просто копируют члены класса. И т.к. B можно скастовать к A, то они ес-но могут использоваться в данном случае. Упрощенно, если ты напишешь функцию:

void copy_object( const A& a );

То ты сможешь вызвать ее и для A, и для B.

anonymous
()

В первом случае работает, потому что slicing. Что, кстати, не очень-то и хорошо. Тупо срезать «лишние» поля и сделать вид, что так и было. Это багофича/фичебаг. Решить можно, унаследовав A как protected.

А во втором случае откуда инфу брать? Вот и нужно явно объявить оператор копирования, чтобы разрулить.

anonymous
()
Ответ на: комментарий от anonymous

В первом случае работает, потому что slicing. Что, кстати, не очень-то и хорошо. Тупо срезать «лишние» поля и сделать вид, что так и было. Это багофича/фичебаг. Решить можно, унаследовав A как protected.

Это совершенно нормальное поведение для по сути функции:

inline A& operator=(A& p1, const A& p2) { p1.a = p2.a; return p1; }

Которая выбирается из множества в одну функцию (в данном случае). И багофичи тут нет, багофича была бы, если бы присваивание работало в обратную сторону.

anonymous
()
Ответ на: комментарий от anonymous

Это совершенно нормальное поведение для по сути функции:

Так-то да, но много ты знаешь случаев когда слайсинг по делу используется?

DarkEld3r ★★★★★
()

Потому что поскольку тип B унаследован (причем публично, что важно) от A, то b, являясь объектом типа B, также является и объектом типа A в одном лице. А вот a является объектом типа A и больше ничем, поэтому дефолтный оператор присвоения и копирующий конструктор у него есть только для копирования/присвоения типа A.

asaw ★★★★★
()

Кто-то уже про усечение сказал?

try {
    throw some_child_of_std_exception( "blablabla", 100, 100.1 )
} catch( const std::exception e ) {
    std::cout << e.what( );
}

try {
    throw some_child_of_std_exception( "blablabla", 100, 100.1 )
} catch( const std::exception &e ) {
    std::cout << e.what( );
}

Чем отличаются?

anonymous
()
Ответ на: комментарий от asaw

Написал я и подумал, что ничего толком не объяснил.

Вот так:

class A
{
public:
    int a;
};

class B : public A
{
public:
    int b;
};


int main()
{
    A a;
    B b;
    a = b; // 1
    static_cast<A>(b) = a; // 2
    return 0;
}

- будут работать оба присвоения. Просто в первом случае приведение типов неявное, а во втором - явное.

asaw ★★★★★
()
Ответ на: комментарий от asaw

будут работать оба присвоения

Не будут, надо static_cast<A&>, а так ты присваиваешь значение временному объекту.

anonymous
()
Ответ на: комментарий от anonymous

Кто-то уже про усечение сказал?

Майерс четверть века назад. ОП, читай его книги, пригодится.

mix_mix ★★★★★
()
Ответ на: комментарий от anonymous

Ну да, ошибочка. Собственно, вот С++ не дает так легко выстрелить себе в ногу)

asaw ★★★★★
()
Ответ на: комментарий от asaw

Зачем ты это мне пишешь? Это уже форменное дрочерство на такое внимание обращать.

Это не дрочерство, это понимание основ С++. Не знаешь основ - этот язык не для тебя.

anonymous
()
Ответ на: комментарий от asaw

к основам это не имеет никакого отношения

LOL

anonymous
()
Ответ на: комментарий от anonymous

Правильно ли я понимаю, что при присваивании A = B, то происходит такое дефолтное усечение лишних полей, и по С++ позволяет такое неявное преобразование B к A. Но вот при присваивании B = A компилятор не разрешает неявное преобразование, и нужно явно преобразовывать?

zamazan4ik ★★
() автор топика

В A создается дефолтный operator=, который принимает в качестве аргумента константную ссылку на A, а так как это ссылка, то туда можно подсунуть не A, а дочерний класс a, потому что по ссылкам работает полиморфизм.

hlebushek ★★
()
Ответ на: комментарий от anonymous

Второй способ, хочешь сказать, работает?

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.