1. 程式人生 > >2. 友元和靜態成員

2. 友元和靜態成員

存在的意義: 當把類的成員的訪問許可權定義為private或者protected時,在類外只能通過公有函式成員訪問,有時候頻繁呼叫函式成員,必然降低程式執行效率。 友元的作用: 友元的作用是提高程式的執行效率,它可以直接訪問類的私有和保護成員,但也因此破壞了類的封裝性,應謹慎使用。 表現形式: 友元可以是一個函式,也可以是一個類。前者是友元函式,後者是友元類。

2.1 友元函式:

定義:在定義一個類時,若在類中用關鍵字freend關鍵字修飾函式,則該函式就成為該類的友元函式,它可以訪問該類中的所有成員。

friend <type> FuncName(<args>);

例項:

class Person {
    char name[10];
    char sex[4];
    Date birthday;
public:
    Person(const char *name, const char *sex, int y, int m, int d);
    friend void print(Person p1);
};

友元函式在類外的定義如下:

void print(Person p1)
{
    printf("姓名:%s\n性別:%s\n出生日期:%d年%d月%d日\n", p1.name, p1.sex, p1.birthday.Getyear(), p1.birthday.Getmonth(), p1.birthday.Getday());
    std::cout << p1.name << '\n';
}

由此可見,可以直接使用p1.name來訪問資料成員,不再需要通過呼叫公有函式來訪問。

關於友元函式使用有如下注意點: 友元函式必須在類的定義中說明 友元函式不是類的成員函式,所以不帶this指標,因此必須將物件名或物件的應用作為友元函式的引數,並在函式體內使用’.'來訪問物件的成員。 友元函式可以直接訪問類中的所有成員 一個類的成員函式也可以作為另一個類的友元函式在宣告這個友元函式時需要在函式名前面加上它的型別和作用域運算子“::”。如下:

class A{
    ...
    int f(...);
};
class B{
    friend int A::f(...);
};

2.2 友元類

若宣告A類為B類的友元類,則A類的所有成員函式都成為B類的友元函式。通過友元類的宣告,友元類A的成員函式可以通過物件名直接訪問到B類物件隱藏的資料。

如下是類Date的定義

class Date {
    int year,month,day;
public:
    int Getyear() { return year; }
    int Getmonth() { return month; }
    int Getday() { return day; }
    Date(int year, int month, int day) { this->year = year, this->month = month, this->day = day; std::cout << "定義的Date建構函式\n"; }
    Date() { std::cout << "預設的Date建構函式\n"; }
    friend class Person;

如下是類Person的函式成員

void Person::print()
{
    printf("姓名:%s\n性別:%s\n出生日期:%d年%d月%d日\n", name, sex, birthday.year, birthday.month, birthday.day);
    std::cout << name << '\n';
}

可以看到,類Date為類Person的友元類,所以在類Person的成員函式中可以直接訪問類Date的資料成員。

注意: 友元關係是不傳遞的 友元關係不能繼承,因為友元函式不是類的成員函式,所以不存在寄存關係 謹慎使用友元,因為其破壞封裝性

2.3 類的靜態成員

靜態成員主要用來解決一個類的不同物件之間的資料和函式共享問題。

2.3.1 靜態資料成員

類的資料成員在類的每一個物件中都有自己的儲存空間,但類的靜態資料成員不同,對同類的多個物件,靜態資料成員只佔有統一個儲存空間,定義如下:

class Student{
    static int count;
};

由於類是一種資料型別,所以只有在定義類時不會分配儲存空間,也就不會為靜態資料成員分配儲存空間,所以靜態資料成員在使用前需要在檔案作用域做定義性說明,以分配儲存空間和初始化。靜態資料成員定義性說明的格式為:(注意需要在函式外定義,若在主函式定義會報錯。)

<資料型別> <類名>::<靜態資料成員名>=<值>;
eg: 
    int Student::count=0;

這裡,在資料成員名的前面不加關鍵字static。訪問類的靜態資料成員的方法是:

<類名>::<靜態資料成員名>
eg:
    Student::count;

2.3.2 靜態成員函式

作用:因為靜態成員先於物件存在儲存空間,所以如何訪問不生成物件的類的靜態成員資料呢?

為了在不生成物件的情況下,直接訪問靜態資料成員,定義了靜態成員函式的概念。定義靜態成員函式的格式如下:

static 返回值型別 成員函式名(引數表);
eg:
    static int AddCount();

**在靜態成員函式的實現中,可以直接訪問該類的靜態資料成員,但不能直接訪問非靜態資料成員,因為類的靜態成員不含this指標。如果要訪問非靜態資料成員,必須通過引數傳遞得到物件名,然後再通過物件來訪問。**例程如下:

//類Person中有靜態資料成員 count和靜態成員函式count_f()

class Person {
    static int count;
    char name[10];
    char sex[4];
    Date birthday;
public:
    Person(const char *name, const char *sex,Date p1);
    void print();
    Person(const char *name, const char *sex, int y, int m, int d);
    static int count_f();
};

靜態成員函式的定義如下:

int Person::count_f()
{
    return count;
}

在主函式中呼叫如下:

int Person::count = 0;
int main()
{
    std::cout << "人數:" << Person::count_f()<<'\n';
    Date d1(1992,2,25);
    Person p1("李明", "男",d1);
    Person p2("李明", "男", 1992,3,24);
    p1.print();
    p2.print();
    std::cout << "人數:" << Person::count_f() << '\n';
    return 0;

可以看出當沒有類的物件時,照樣可以使用該靜態成員函式訪問靜態資料成員。

當靜態成員函式如下:

int Person::count_f()
{
    std::cout << this->name << '\n';
    return count;
}

編譯器會提示,this只能用於非靜態成員函式內部,然後報錯。