整理日: 2015年03月18日ios
在 C++ 中,操做符(運算符)能夠被重載以改寫其實際操做。同時咱們能夠定義一個函數爲類的朋友函數(friend function)以便使得這個函數可以訪問類的私有成員,這個定義一般在頭文件中完成。c++
在Visual C++中定義通常的函數爲朋友函數一般是沒有問題的。然而對某些重載操做符的函數,即便咱們將它們定義爲類的朋友函數,VC的編譯器仍然會顯示出錯信息,認爲這些朋友函數無權訪問類的私有成員。我認爲這應該是VC6.0的bug。函數
如下代碼就是個例子:spa
// 頭文件 "Sample.h" #include<iostream> 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"<<endl; in >> s.x ; return in; } ostream &operator<<(ostream &out, const Sample s) { cout << s.x << endl; return out; }
以上代碼在gnuc++中編譯運行毫無問題。可是在VC++6.0中編譯的時候就會出現如下的編譯錯誤:code
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中解決這個問題有如下幾種方法:ci
在頭文件中實現做爲朋友函數的操做符函數的重載,也就是說在實現文件」Sample.cpp」中將函數重載的實現去掉,而將頭文件修改以下:原型
// 修改後的頭文件 1 "Sample.h" #include<iostream> 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"<<endl; in >> s.x ; return in; } private: int x; };
在頭文件中類定義以前將類和朋友操做符函數的原型特別聲明一下,也就是將頭文件修改以下(實現文件」Sample.cpp」不用做任何修改):編譯器
// 修改後的頭文件 2 "Sample.h" #include<iostream> 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; };
第三種方法是對I/O名空間的使用實行明確聲明,也就是說在頭文件」Sample.h」中直接寫:io
#include<iostream> using std::ostream; using std::istream ….
取代 「using namespace std;」
注意:在這個例子裏咱們在實現文件 「Sample.cpp」中包含 「using namespace std;」這句話,不然在實現中就不能使用 「cout」 , 「cin」, 「<< 「, 「>>」 和 endl 這些關鍵字和符號。修改後的完整代碼以下:編譯
// Sample.h #include<iostream> 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"<<endl; in >> s.x ; return in; }*/ private: int x; }; // "Sample.cpp" #include "Sample.h" using namespace std; Sample::Sample() { x=5; } istream &operator>>(istream &in, Sample & s) { cout<<"Please enter a value"<<endl; in >> s.x ; return in; } ostream &operator<<(ostream &out, const Sample s) { cout << s.x << endl; return out; }