通过声明操作的朋友,你告诉编译器查找功能
ostream& operator<<(ostream &,T);
其中T
是完全相同的类型B树类模板进行实例化。 (例如:btree<Node>
,实际签名会ostream& operator<<(ostream &, Node);
- 假设你HACE成员i
和Node
型n
)
此功能将可以访问类btree<T>
的private和protected成员(变量和函数)的所有实例T
,但它实际上并不是该类的成员(因为它不包含friend
关键字)。
操作定义您提供的是一个操作符是模板类B树中的一员,因为如果你有宣布
template<class T>
class btree
{
public:
ostream& operator<<(ostream &,T);
};
这是由于包含的是btree<T>::
前缀(即指定功能/操作员属于哪个类)。
由于该类中没有相应的运算符声明(请参阅上述对朋友声明的描述),因此编译器会抱怨。
要解决它,你要么
- 保持朋友声明,删除操作确定指标的
btree<T>::
前缀和template<class T>
并更改第二个参数类型btree<Type>&
,其中Type
是的一个你期望btree模板被实例化的类型(例如Node
) - 然后为其他类型提供类似的定义。
- 或移除声明的
friend
关键字在类和从两个声明和定义如现在操作者应该对整个B树工作(可经由隐式地提供除去T
参数*this
)。
- 或者,你可以声明朋友经营者作为模板进行实验,但需要更多的修改:(阅读更多关于forward declaration)
template<class T> btree; // forward declaration of class btree
// forward declare operator (or move definition here)
template<class T>
ostream& operator<<(ostream &o, btree<T>& s);
// declare operator as template friend
template<class T>
class btree
{
public:
friend ostream& operator<< <> (ostream &, bree<T>&);
// note <> after operator name to denote template with no new template parameters
};
注意,上面我认为你想输出整棵树(即在btree对象上调用operator<<
)。从代码中不清楚这是否是你的意图(class btree没有成员i
和n
)。 如果不是,并且您想要调用运算符的类型是btree的实际模板参数,则不需要从T
更改模板运算符的第二个参数,但是也不需要声明它作为类btree的friend
作为运算符独立于btree。如果i
和/或n
在该类别中是私密的,则您确实需要将其声明为类别的朋友,该类别的成员i
和n
您正在访问定义者(例如上面的节点)。关于丢失btree<T>::
(或Node::
)的概念仍然适用,因为运营商不属于任何类别。
夫妇更多的事情,假设你去与朋友声明:
- 到操作的类型,第二个参数应该是
btree<T>&
(强调&
),因为它是更有效地传递reference到btree对象比复制整个btree(或使用指针的浅拷贝并使用缺省copy-contructor)
- 第二个参数也应该标记为
const
,因为(可能)您不希望在更改btree对象期间输出。请注意,在这种情况下,您需要将btree<T>
中的某些不变方法标记为const
以允许它进行编译。 (参见const correctness的FAQ)
EDIT'd几次说清楚,并确保正确性
http://sscce.org/(尤其是** **简单)。 – Griwes 2012-03-26 15:47:08
该代码看起来很冗长,但问题出现在类btree以及紧随该类之后的重载<<运算符函数中。 – user1232138 2012-03-26 15:57:47
@OP,每当我看到如此高的滚动条时,就表示错误的测试用例。删除必要的内容,然后它将是“简单,自包含的正确示例”。 – Griwes 2012-03-26 16:05:50