我用C ++编写了一个简单的二叉树类,并希望为它添加一个输出运算符。我的第一次尝试是:
ostream& operator<<(ostream& out, const Tree& tree) {
out << tree.myData;
if (tree.myLeft)
out << "(" << (*tree.myLeft) << ")";
if (tree.myRight)
out << "[" << (*tree.myRight) << "]";
return out;
}
(其中myLeft和myRight分别指向当前树的左右子)。这是正确的,但是,它不够酷,因为它跨越几行并且需要多次写“out <<”。
作为创建单行操作符的尝试,我写道:
ostream& operator<<(ostream& out, const Tree& tree) {
return (out << tree.myData
<< "(" << (tree.myLeft? *tree.myLeft: "") << ")"
<< "[" << (tree.myRight? *tree.myRight: "") << "]");
}
但是,这会产生错误:
不兼容的操作数类型('Tree'和'const char [1]')
所以我尝试了这个:
ostream& operator<<(ostream& out, const Tree& tree) {
return (&tree?
out << tree.myData
<< "(" << *(tree.myLeft) << ")"
<< "[" << *(tree.myRight) << "]":
out);
}
这适用于我的计算机,但会生成警告,暗示这是未定义的行为:
在明确定义的C ++代码中,引用不能绑定到取消引用的空指针;可以假设指针总是转换为true [-Wundefined-bool-conversion]
问题:有没有办法在简单的单个语句中编写此输出运算符?
一个简单而优雅的解决方案是重新设计您的树,使其无需空指针。相反,将当前使用的空指针替换为指向具有与空树一致的行为的标记树节点的指针。
然后,您可以重写输出流运算符,如下所示:
ostream& operator<<(ostream& out, const Tree& tree) {
if (&tree == &Tree::NULL_TREE_SENTINEL) return out;
return out << tree.myData
<< "(" << *tree.myLeft << ")"
<< "[" << *tree.myRight << "]";
}
(这假设在Tree
内部有一个相应的静态成员,哨兵就像麒麟一样指向它们。)
或者,sentinel树节点可以是具有此行为的Tree
的子类的实例。这有时被称为null object pattern。但是,它需要动态调度(即通过虚拟成员函数的运行时多态性)才能工作。
除此之外,您还没有正确诊断第二个代码的问题:
这适用于我的电脑
它似乎工作但实际上并没有。我不知道在什么样的情况下代码实际上会做一些令人讨厌的事情。但是要明确的是,由于子表达式*(tree.myLeft)
和*(tree.myRight)
,你的代码是非法的:这些表达式是取消引用空指针,这从来都不合法。您收到的有关&tree
测试的警告消息仅仅是先前错误的症状。