我有一个A类,我为其定义了一个(重载)流插入运算符。我公开从这个A类派生出一个B类,它有一个额外的数据成员。因此,我需要重新定义派生类的重载流插入运算符,我这样做:
#include <iostream>
using namespace std;
class A {
int i;
char c;
public:
A(int i = 0, char c = ' ') {
this->i = i;
this->c = c;
}
friend ostream& operator << (ostream&, const A&);
};
class B : public A {
double d;
public:
B(int i = 0, char c = ' ', double d = 0.0) : A(i, c), d(d) {}
friend ostream& operator << (ostream&, const B&);
};
ostream& operator << (ostream& out, const A& a) {
out << "\nInteger: " << a.i << "\nCharacter: " << a.c << endl;
return out;
}
ostream& operator << (ostream& out, const B& b) {
out << b;
out << "\nDouble: " << b.d << endl;
return out;
}
int main() {
A a(10, 'x');
B b(20, 'y', 5.23);
cout << b;
return 0;
}
问题1:这是一种合适的技巧吗?如果没有,请让我知道我哪里出错。
问题2:运行时,此程序崩溃。为什么这样?
答案 0 :(得分:2)
支持此操作的一种常见方法是让重载的运算符调用虚拟成员函数:
class A {
public:
virtual std::ostream &write(std::ostream &os) const {
// write self to os
os << "A\n";
return os;
}
};
class B : public A {
public:
virtual std::ostream &write(std::ostream &os) const {
// write self to os
// This can use the base class writer like:
A::write(os);
os << "B\n";
return os;
}
};
然后运算符重载只调用该成员函数:
std::ostream &operator<<(std::ostream &os, A const &a) {
return a.write(os);
}
由于write
是虚拟的,并且您正在通过(const)引用传递A
,因此会根据实际类型调用正确的成员函数(即A::write
if该对象实际上是A
的实例,如果它是B::write
的实例,则为B
。
例如,我们可以运用这样的东西:
int main() {
A a;
B b;
std::cout << a << "\n";
std::cout << b << "\n";
}
...产生这样的输出:
A
A
B
在实际使用中,您可能希望保护write
个功能,并使operator<<
成为A
的朋友。
答案 1 :(得分:0)
程序崩溃是因为你的第二个插入操作符自行调用:
print(ostream&) const
通常这是一个很好的方法,虽然我更喜欢给类一个公共虚拟{{1}}函数,并让插入操作符调用它。