C++編程思想學習筆記---第五章 隱藏實現

第5章 隱藏實現


一、C++的訪問控制符

public 在其後聲明的所有成員可以被所有人訪問。

private 表示除了該類型的創建者類的內部成員函數之外,任何人都不能訪問。

protected 繼承的結構可以訪問protected成員,但不能訪問private結構


二、友元:朋友才能看到

C++是一種很“人性化”的語言,跟我不熟的人,都不能知道我家的家庭成員。朋友就可以。

可以聲明爲友元的函數類型:

1、全局函數(可以用本結構的指針作爲參數)

2、另一個結構中的函數(可以用本結構的指針作爲參數)

3、整個另一個結構

friend的雙重聲明作用:1) 聲明一個函數

   2) 聲明這個函數爲當前結構的友元


開個小差:書中有這樣一個代碼段

struct X;

struct Y{
    void f(X*);
};

結構Y要聲明其成員函數f(X*),必須知道X的定義,但X結構體又是在結構Y之後明確定義的。這種情況下可以在前面先聲明一個struct X。函數要傳遞的是一個地址,不關X是什麼類型,其類型的地址都是一個固定的值,因此編譯器知道如何傳遞一個地址。編譯是可以通過的。

但是如果聲明這樣一個函數void f(X);就不行了,因爲編譯器還不知道X的具體結構,編譯會報錯。


三、嵌套友元

嵌套的結構並不能自動獲得訪問private成員的權限。若遵循下列規則就可以

1、聲明一個嵌套結構

2、聲明該結構爲全局範圍的friend

3、定義這個結構

主要就是將聲明結構與聲明友元分開~!

struct Holder{
private:
	int a[sz];
public:
	void initialize();
	struct Pointer;
	friend Pointer;
	struct Pointer{
	private:
		Holder* h;
		int* p;
	public:
		void initialize(Holder* h);
		void next();
		void previous();
		void top();
		void end();
		int read();
		void set(int i);
	};
};

這樣,結構Pointer就可以直接訪問數組a了。

再做個試驗,在public區域定義一個變量int n; 如果並沒有聲明結構Pointer是結構Holder的友元,結構Pointer的函數仍然能夠訪問數據成員n。這說明,friend關鍵字是用來讓外部函數訪問類的私有成員的一種方法!!!

從第三點看出,C++並非一個純面向對象的語言,friend關鍵字用來解決一些實際問題。


五、類

關鍵字class被用來描述一個新的數據類型。它和struct的每一個方面都是一樣的,不同在於

class聲明的類中的成員默認爲private;

struct聲明的結構體中的成員默認爲public;


六、現在以C++的方式來實現一個Stash

#ifndef STASH_H
#define STASH_H

class Stash{
	int size;	//number of each spaces
	int quantity;	//number of storage spaces
	int next;	//Next empty space
	//Dynamically allocated array of bytes:
	unsigned char* storage;
	void inflate(int increase);
public:
	void initialize(int size);
	void cleanup();
	int add(void* element);
	void* fetch(int index);
	int count();
};
#endif//STASH_H
注意到函數void inflate(int increase);被加入到了private裏面,因爲它只在add(入棧時發現空間不夠用了才調用),所以不能被輕易訪問,事實上它也確實不需要成爲一個外部接口。


七、句柄類

先說一個實際的問題。對於一個公司的核心技術,技術管理人員可能不想所有人都能看到其代碼,因此交給其他程序員使用的時候,可能是交給他們一個庫文件,一個頭文件。只要在頭文件裏能找到的接口,都可以調用。另一個事實是,當一個文件被修改,或它所依賴的頭文件被修改,都需要重複編譯該文件。這意味着程序員無論何時修改了一個類,無論修改的是公共接口的部分還是私有成員的聲明部分,他都必須編譯包含這個頭文件的所有文件。這就是通常所說的易碎的基類問題(fragile base-class problem)對於一個大項目而言,這是非常耗時耗力的。
解決辦法是----句柄類(handle class)。有關實現的任何東西都消失了,只剩一個單指針“smile"。改指針指向一個結構,該結構的定義與其所有的成員函數的定義一同出現在實現文件中。這樣,只要接口部分不改變,頭文件就不需要變動。兒實現部分可以任意更改,編譯的時候只需編譯單獨地一個文件就OK。

#ifndef HANDLE_H
#define HANDLE_H

class Handle{
	struct Cheshire;
	Cheshire *smile;
public:
	void initialize();
	void cleanup();
	int read();
	void change(int);
};
#endif
在頭文件中並沒有定義結構體Cheshire。只是聲明瞭而已,但是這對於Cheshire類型的指針smile已經足夠,編譯器已經知道它是一個地址。

接下來你只需要在實現文件Handle.cpp裏實現對結構Cheshire的定義即可。

#include<iostream>
#include "Handle.h"
using namespace std;

struct Handle::Cheshire{
	int i;
};

void Handle::initialize()
{
	smile = new Cheshire;
	smile->i = 0;
}

void Handle::cleanup()
{
	delete smile;
	smile = NULL;
}

int Handle::read()
{
	return smile->i;
}

void Handle::change(int i)
{
	smile->i = i;
}

int main()
{
	Handle h;
	h.initialize();
	cout << "smile->i = " << h.read() << endl;
	h.change(5);
	cout << "smile->i = " << h.read() << endl;

	return 0;


發佈了27 篇原創文章 · 獲贊 6 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章