友元例項:友元類及友元函式
學習了c++這麼久,一直沒有對友元進行了解,據說友元不是特別好用(據說,不是我說的),因此直到今天才去了解。其實友元確實不是很常用,但友元功能確實很實用,它不但能夠釋放類中的非公有成員,同時還能保證了類的封裝性。使用者可以有選擇為具體的類或函式賦予“通行證”。還是比較靈活的。比如:某個類去訪問另一個類的私有成成員,或者一個函式去訪問某個類的私有成員等等,都可以使用友元來實現。
下面就友元做了兩個小例子,望高手指教。(每段程式碼都在不同的檔案中)
首先是關於友元類的程式碼,就一句話,很簡單。。。
Test.h:
#ifndef TEST_H #define TEST_H #include<iostream> using namespace std; class Test { friend class FriendTest; //此處宣告FriendTest為Test的友元類,FriendTest類可以訪問Test的私有成員 public: Test(); void set(int h,int w); void print(); virtual ~Test(); protected: private: int height; int weight; }; #endif // TEST_H
Test.cpp
#include "../include/Test.h"
Test::Test()
{
//ctor
height = 0;
weight = 0;
}
void Test::set(int h, int w)
{
height = h;
weight = w;
}
void Test::print()
{
cout << height << " ";
cout << weight <<endl;
}
Test::~Test()
{
//dtor
}
下面關於FriendTest的相關程式。
FriendTest.h
#ifndef FRIENDTEST_H
#define FRIENDTEST_H
#include "Test.h"
class FriendTest
{
public:
FriendTest();
void setTest(Test& t, int h, int w);
virtual ~FriendTest();
protected:
private:
};
#endif // FRIENDTEST_H
FriendTest.cpp
#include "../include/FriendTest.h" FriendTest::FriendTest() { //ctor } void FriendTest::setTest(Test& t, int h, int w) //之前聲明瞭友元,所以此處可以呼叫私有成員 { t.height = h; t.weight = w; } FriendTest::~FriendTest() { //dtor }
#include <iostream>
#include "./include/Test.h"
#include "./include/FriendTest.h"
using namespace std;
int main()
{
Test t;
FriendTest ft;
t.set(30, 20);
ft.setTest(t,9,8);
t.print();
return 0;
}
接下來是關於友元函式的問題,友元函式我弄了很久,對於某個類來說,只希望其某個函式為友元,需要對函式進行友元宣告。然而將上邊程式碼中的友元類的宣告改成友元函式的宣告,編譯不通過,提示未定義。後來發現對於友元函式來說兩個類必須放在同一個檔案中,並且要有部分調整,具體實現如下,並富有詳解。
部分程式碼省略。。。主要程式碼如下:
#include <iostream>
using namespace std;
//由於兩個類都使用到了另一個類,所以順序很關鍵。如果將兩個類的順序顛倒會出現編譯不通過,並提示未定義。另外友元函式必須在最後實現,因為它用到了兩個類中的成員。仔細與上一部分的程式碼比較,你便會了解裡邊的玄機。。。
class Test; //首先需要宣告Test類,FriendTest類中需要使用。
class FriendTest
{
public:
FriendTest();
void setTest(Test& t, int h, int w);
virtual ~FriendTest();
protected:
private:
};
class Test
{
friend void FriendTest::setTest(Test& t, int h, int w); //友元函式宣告
public:
Test();
void set(int h,int w);
void print();
virtual ~Test();
protected:
private:
int height;
int weight;
};
void FriendTest::setTest(Test& t, int h, int w)
{
t.height = h;
t.weight = w;
}
int main()
{
cout << "friend" <<endl;
Test t;
FriendTest ft;
t.set(30, 20);
ft.setTest(t,9,8);
t.print();
return 0;
}
另外在網上看到了一個關於primer c++中一個友元例子的講解可能對你理解有些幫助:
做了部分修改。。。。。。
第一種寫法問題:
編譯到Screen時,由於Screen類使用到Window_Mgr的成員函式,前面給出了Window_Mgr的宣告,但不清楚Window_Mgr的完整定義,對成員函式不清楚,所以友元函式宣告不成立,編譯出錯。
class Window_Mgr
class Screen
{
public:
friend Window_Mgr& Window_Mgr::relocate(Window_Mgr::index r, Window_Mgr::index c, Screen& s);
private:
int height;
int width;
}
class Window_Mgr
{
public:
typedef std::string::size_type index;
Window_Mgr& Window_Mgr::relocate(index r, index c, Screen& s)
{
s.height += r;
s.width += c;
return *this;
}
}
第二種寫法問題在於:
編譯到relocate時,由於Screen& s的實現使用到Screen的成員變數,雖然前面給出了Screen的宣告,但此時還不清楚Screen的完整定義,所以編譯出錯。
class Screen;
class Window_Mgr
{
public:
typedef std::string::size_type index;
Window_Mgr& Window_Mgr::relocate(index r, index c, Screen& s)
{
s.height += r;
s.width += c;
return *this;
}
}
class Screen
{
public:
friend Window_Mgr& Window_Mgr::relocate(Window_Mgr::index r, Window_Mgr::index c, Screen& s);
private:
int height;
int width;
}
第三種寫法:
將Window_Mgr::relocate的實現移動到最後,由於編譯類Window_Mgr時,並不需要Screen&s 的實現細節,問題得到解決
class Screen;
class Window_Mgr
{
public:
typedef std::string::size_type index;
Window_Mgr& Window_Mgr::relocate(index r, index c, Screen& s); //無內部成員的使用
}
class Screen
{
public:
friend Window_Mgr& Window_Mgr::relocate(Window_Mgr::index r, Window_Mgr::index c, Screen& s);
private:
int height;
int width;
}
Window_Mgr& Window_Mgr::relocate(Window_Mgr::index r, Window_Mgr::index c, Screen& s)
{
s.height += r;
s.width += c;
return *this;
}
可見,這兩個類如果編譯成功需要嚴格的交替順序
這也就解釋了為什麼放在兩個檔案中無法編譯。
附錄:
一開始的實現的不能編譯的兩個檔案
實現分別如下:Window_Mgr.h
#ifndef WINDOW_MGR //為了避免兩個檔案巢狀
#define WINDOW_MGR
#include <string>
#include <Screen.h>
class Window_Mgr
{
public:
typedef std::string::size_type index;
Window_Mgr& Window_Mgr::relocate(index r, index c, Screen& s)
{
s.height += r;
s.width += c;
return *this;
}
}
#endif
Screen.h
#ifndef SCREEN
#define SCREEN
#include "Window_Mgr.h"
class Screen
{
public:
friend Window_Mgr& Window_Mgr::relocate(Window_Mgr::index r, Window_Mgr::index c, Screen& s);
private:
int height;
int width;
}
#endif