Виртуальная дружественная функция
#новичкам
Вчера мы поговорили о том, что таких функций не бывает, но очень хочется получить альтернативу. Хочется изменять работу функции в зависимости от динамического типа, который в нее передается.
Ну и на самом деле ничего сложного здесь нет. Можно ведь сделать полиморфный метод, который будет вызываться в этой функции. И вот его поведение мы можем изменять примерно как нашей душеньке захочется.
Рассмотрим банальный пример -
сериализация объекта в поток. Обычно для такой задачи используют дружественный оператор <<. Но вот хотелось бы сериализовать в зависимости от динамического типа. Фигня вопрос.
struct Person {
Person(const std::string &first_name,
const std::string &last_name) : first_name_{first_name},
last_name_{last_name} {}
friend std::ostream& operator<<(std::ostream& o, const Person& b) {
return o << b.to_str();
}
protected:
virtual std::string to_str() const{
return first_name_ + " " + last_name_;
}
private:
std::string first_name_;
std::string last_name_;
};
struct TaxPayer : Person {
TaxPayer(const std::string first_name,
const std::string last_name,
const std::string itn) : Person{first_name, last_name}, itn_{itn} {}
protected:
virtual std::string to_str() const{
return Person::to_str() + " " + itn_;
}
private:
std::string itn_;
};
int main() {
auto prs1 = std::make_unique<Person>("Ter", "Minator");
auto prs2 = std::make_unique<TaxPayer>("Ace", "Ventura", "0000");
std::cout << *prs1 << std::endl;
std::cout << *prs2 << std::endl;
}
// OUTPUT:
// Ter Minator
// Ace Ventura 0000
Есть у нас класс человека с его именем и фамилией. Есть класс налогоплательщика, который наследуется от человека и добавляет к полям ИНН. Допустим, мы хотим как-то выводить на консоль содержимое этих людей(в смысле поля; расчленением мы не занимаемся, не в Питере живем все-таки). Можно конечно в каждом классе определять свой оператор или выводить на консоль результат работы метода to_str, но это лишний апи и лишний код.
Мы просто в базовом классе определяем другана и говорим, чтобы он вызывал виртуальный метод. И все.
Да, это очень просто. Но подход скрытия деталей реализации за закрытым виртуальным методом используется, например в
идиоме невиртуального интерфейса и еще невесть где. Поэтому о даже о таком приеме надо знать и применять его в подходящих ситуациях.
Have a real friends. Stay cool.
#cppcore