VC6.0 中重载操作符函数无法访问类的私有成员 在 C++ 中,操作符(运算符)可以被重载以改写其实际操作。 同时我们可以定义一个函数为类的朋友函数(friend function)以便使得这个函数能够访问类 的私有成员, 这个定义通常在头文件中完成。 在 Visual C++中定义一般的函数为朋友函数通常是没有问题的。 然而对某些重载操作符的函数, 即使我们将它们定义为类的朋友函数,VC 的编译器仍然会显示出错信息, 认为这些朋友函数无权访问类的私有成员。 我认为这应该是 VC6.0 的 bug。 以下代码就是个例子: // 头文件 “Sample.h” #include
using namespace std; class Sample { public: Sample(); friend ostream &;operator<<(ostream &;out, const Sample s); friend istream &;operator>>(istream &;in, Sample &; s); private: int x; }; // 实现文件 “Sample.cpp” #include “Sample.h” Sample::Sample() { x=0; } istream &;operator>>(istream &;in, Sample &; s) { cout<<”Please enter a value”<> s.x ; return in; } ostream &;operator<<(ostream &;out, const Sample s) { cout << s.x << endl; return out; }
以上代码在 gnuc++中编译运行毫无问题。 但是在 VC++6.0 中编译的时候就会出现以下的编 译错误: Compiling… Sample.cpp c:\temp\sample.cpp(8) : error C2248: ‘x’ : cannot access private member declared in class ‘Sample’ c:\temp\sample.h(19) : see declaration of ‘x’ c:\temp\sample.cpp(13) : error C2248: ‘x’ : cannot access private member declared in class ‘Sample’ c:\temp\sample.h(19) : see declaration of ‘x’ Error executing cl.exe.Sample.obj - 2 error(s), 0 warning(s) 在 VC++ 6.0 中解决这个问题有以下几种方法: 1. 在头文件中实现作为朋友函数的操作符函数的重载,也就是说在实现文 件”Sample.cpp”中将函数重载的实现去掉,而将头文件修改如下: // 修改后的头文件 1 “Sample.h” #include using namespace std; class Sample { public: Sample(); friend ostream &;operator<<(ostream &;out, const Sample s); friend ostream &;operator<<(ostream &;out, const Sample s) { cout << s.x << endl; return out; } friend istream &;operator>>(istream &;in, Sample &; s); friend istream &;operator>>(istream &;in, Sample &; s) { cout<<”Please enter a value”<> s.x ; return in; } private: int x; }; 2. 在头文件中类定义之前将类和朋友操作符函数的原型特别声明一下,也就是将头文 件修改如下(实现文件”Sample.cpp”不用作任何修改):
// 修改后的头文件 2 “Sample.h” #include using namespace std; // 以下 3 行代码为新加入 class Sample; ostream &;operator<<(ostream &;out, const Sample s); istream &;operator>>(istream &;in, Sample &; s); class Sample { public: Sample(); friend ostream &;operator<<(ostream &;out, const Sample s); friend istream &;operator>>(istream &;in, Sample &; s); private: int x; }; 3. 第三种方法是
对 I/O 名空间的使用实行明确声明,也就是说在头文件”Sample.h”中 直接写: #include using std::ostream; using std::istream …. 取代 “using namespace std;” 注意:在这个例子里我们在实现文件 “Sample.cpp”中包含 “using namespace std;” 这句话,否则在实现中就不能使用 “cout” , “cin”, “<< “, “>>” 和 endl 这些关键字和 符号。修改后的完整代码如下:
// Sample.h #include using std::istream; using std::ostream; class Sample { public: Sample(); friend ostream &;operator<<(ostream &;out, const Sample s);
/*friend ostream &;operator<<(ostream &;out, const Sample s) { cout << s.x << endl; return out; }*/ friend istream &;operator>>(istream &;in, Sample &; s); /*friend istream &;operator>>(istream &;in, Sample &; s) { cout<<”Please enter a value”<> s.x ; return in; }*/ private: int x; }; // “Sample.cpp” #include “Sample.h” using namespac