Здесь представлены две взаимодействующие функции:
- Операторы присваивания никогда не наследуются
- Неявный конструктор или оператор преобразования (
operator T()
) определяют пользовательское преобразование, которое можно неявно использовать как часть последовательности преобразования
Операторы присваивания никогда не наследуются
Простой пример кода:
struct Base {}; // implicitly declares operator=(Base const&);
struct Derived: Base {}; // implicitly declares operator=(Derived const&);
int main() {
Derived d;
Base b;
d = b; // fails
}
с ideone :
prog.cpp: In function ‘int main()’:
prog.cpp:7: error: no match for ‘operator=’ in ‘d = b’
prog.cpp:2: note: candidates are: Derived& Derived::operator=(const Derived&)
Последовательность преобразования
Всякий раз, когда есть несоответствие "импеданса", например, здесь:
Derived::operator=
ожидает Derived const&
аргумент
- a
Base&
предоставляется
компилятор попытается установить последовательность преобразования для преодоления разрыва. Такая последовательность преобразования может содержать в большинстве одно пользовательское преобразование.
Здесь он будет искать:
- любой конструктор
Derived
, который можно вызвать с помощью Base&
(не явно)
- оператор преобразования в
Base
, который даст Derived
item
Нет Base::operator Derived()
, но есть конструктор Derived::Derived(Base const&)
.
Поэтому наша последовательность конвертации определена для нас:
Base&
Base const&
(тривиально)
Derived
(с использованием Derived::Derived(Base const&)
)
Derived const&
(временный объект привязан к константной ссылке)
А потом Derived::operator(Derived const&)
вызывается.
В действии
Если мы дополним код еще несколькими трассами, мы сможем увидеть его в действии .
#include <iostream>
struct Base {}; // implicitly declares Base& operator(Base const&);
struct Derived: Base {
Derived() {}
Derived(Base const&) { std::cout << "Derived::Derived(Base const&)\n"; }
Derived& operator=(Derived const&) {
std::cout << "Derived::operator=(Derived const&)\n";
return *this;
}
};
int main() {
Derived d;
Base b;
d = b;
}
Какие выходы:
Derived::Derived(Base const&)
Derived::operator=(Derived const&)
Примечание. Предотвращение этого?
В C ++ возможно удалить конструктор для использования в последовательностях преобразования. Для этого нужно добавить префикс объявления конструктора, используя ключевое слово explicit
.
В C ++ 0x становится возможным использовать это ключевое слово и в операторах преобразования (operator T()
).
Если здесь мы используем explicit
до Derived::Derived(Base const&)
, то код становится некорректным и должен быть отклонен компилятором.