Настройка поддержки cout в структурах с несколькими уровнями наследования
#include <iostream>
#include <string>
struct Printable abstract
{
friend std::ostream& operator<<(std::ostream& cout, const Printable& obj)
{
obj.print(cout);
return cout;
}
virtual void print(std::ostream& cout) const = 0;
};
struct VirtualBase abstract : public Printable
{
//stuff
};
struct Named abstract : public Printable
{
std::string name;
void print(std::ostream& cout) const
{
cout << "Name: " << name;
}
};
struct DerivedA : public VirtualBase
{
void print(std::ostream& cout) const
{
cout << "DerivedA";
}
};
struct DerivedB : public VirtualBase, public Named
{
void print(std::ostream& cout) const
{
cout << "DerivedB";
dynamic_cast<const Named*>(this)->print(cout);
//Is there a better way to call Named::print?
}
};
Поскольку DerivedB наследует VirtualBase и Named, и оба они наследуют Printable, я не могу использовать DerivedB с cout. Каков наилучший способ обеспечить поддержку печати на нескольких уровнях иерархии наследования? Кроме того, что было бы самым простым способом вызвать Named::print в печати производного класса?
3 ответа
Проблема в том, что DerivedB
это VirtualBase
(который является Printable
) и Named
(который является Printable
), Итак operator<<
пытается конвертировать DerivedB
к Printable
, но не могу опускать руки, потому что это два Printable
объекты, и он не знает, к чему опускаться. Так как вы хотите только DerivedB
происходить от одного Printable
объект, вы должны использовать виртуальное наследование.
normal inheritance: virtual inheritance:
Printable Printable Printable
| | / \
VirtualBase Named VirtualBase Named
\ / \ /
DerivedB DerivedB
Что делается просто:
struct Named abstract : virtual public Printable
struct VirtualBase abstract : virtual public Printable
Обратите внимание, что класс с виртуальным наследованием больше и немного медленнее, чем без него, но, с другой стороны, C++ является одним из немногих языков, которые могут это делать вообще.
Вы просто должны определить, какие print
Вы хотите позвонить с оператором разрешения области (::
) вот так:
Named::print(cout);
Хорошо, я нашел способ исправить это путем шаблонной перегрузки оператора:
template<typename P> friend std::ostream& operator<<(std::ostream& cout, const P& obj)
{
obj.print(cout);
return cout;
}
Я не уверен, насколько это стабильно.