//
item.combine(Sales_data("9-999-99999-9"));
Желательно ли преобразование типа string в Sales_data, зависит от конкретных обстоятельств. В данном случае это хорошая идея. Строка в переменной null_book, вероятнее всего, соответствует несуществующему ISBN.
Преобразование из istream в Sales_data более проблематично:
//
//
item.combine(cin);
Этот код неявно преобразует объект cin в объект класса Sales_item. Это преобразование осуществляет тот конструктор класса Sales_data, который получает тип istream. Этот конструктор создает (временный) объект класса Sales_data при чтении со стандартного устройства ввода. Затем этот объект передается функции same_isbn().
Этот объект класса Sales_item временный (см. раздел 2.4.1). По завершении функции combine() никакого доступа к нему не будет. Фактически создается объект, удаляющийся после того, как его значение добавляется в объект item.
Чтобы предотвратить использование конструктора в контексте, который требует неявного преобразования, достаточно объявить его explicit:
class Sales_data {
public:
Sales_data() = default;
Sales_data(const std::string &s, unsigned n, double p):
bookNo(s), units_sold(n), revenue (p*n) { }
explicit Sales_data(const std::string &s): bookNo(s) { }
explicit Sales_data(std::istream&); //
};
Теперь ни один из конструкторов не применим для неявного создания объектов класса Sales_data. Ни один из предыдущих способов применения теперь не сработает:
item.combine(null_book); //
item.combine(cin); //
Ключевое слово explicit имеет значение только для тех конструкторов, которые могут быть вызваны с одним аргументом. Конструкторы, требующие большего количества аргументов, не используются для неявного преобразования, поэтому нет никакой необходимости определять их как explicit. Ключевое слово explicit используется только в объявлениях конструкторов в классе. В определении вне тела класса его не повторяют.
//
//
explicit Sales_data::Sales_data(istream& is) {
read(is, *this);
}
Одним из контекстов, в котором происходит неявное преобразования, является использование формы инициализации копированием (со знаком =) (см. раздел 3.2.1). С этой формой инициализации нельзя использовать явный конструктор; придется использовать прямую инициализацию:
Sales_data item1(null_book); //
//
//
Sales_data item2 = null_book;
Хотя компилятор не будет использовать явный конструктор для неявного преобразования, его можно использовать для преобразования явно:
//
item.combine(Sales_data(null_book));
//
item.combine(static_cast