一.相关知识点
1. 在C++中,存取控制并不是面向对象的特征,但它为类的创建者提供了很有价值的访问控制。类的用户可以清楚地看到,什么可以用,什么应该忽略。更重要的是,它保证了类的用户不会依赖任何类的实现细节。有了这些,我们就能更改类的实现部分,没有人会因此而受到影响,因为他们并不能访问类的这一部分。一旦我们有了更改实现部分的自由,就可以在以后的时间里改进我们的设计,而且允许犯错误。要知道,无论我们如何小心地计划和设计,都可能犯错误。知道犯些错误也是相对安全的,这意味着我们会变得更有经验,会学得更快,就会更早完成项目。一个类的公共接口部分是用户能看到的。所以在分析设计阶段,保证接口的正确性更加重要。但这并不是说接口不能作修改。如果我们第一次没有正确地设计接口部分,我们可以再增加函数,这样就不需要删除那些已使用该类的程序代码。
2.可见的实现部分
有些项目不可让最终用户看到其实现部分。例如可能在一个库的头文件中显示一些策略信息,但公司不想让这些信息被竞争对手获得。比如从事一个安全性很重要的系统 (如加密算法),我们不想在文件中暴露任何线索,以防有人破译我们的代码。或许我们把库放在了一个“有敌意”的环境中,在那里程序员会不顾一切地用指针和类型转换存取我们的私有成员。在所有这些情况下,就有必要把一个编译好的实际结构放在实现文件中,而不是让其暴露在头文件中。
3.句柄类( handle classes)
C++中的存取控制允许将实现与接口部分分开,但实现的隐藏是不完全的。编译器必须知道一个对象的所有部分的声明,以便创建和管理它。我们可以想象一种只需声明一个对象的公共接口部分的编程语言,而将私有的实现部分隐藏起来。但 C + +在编译期间要尽可能多地做静态类型检查。这意味着尽早捕获错误,也意味着程序具有更高的效率。然而这对私有的实现部分来说带来两个影响:一是即使程序员不能轻易地访问实现部分,但他可以看到它;二是造成一些不必要的重复编译。
二.相关代码
1.
#include <iostream> using namespace std; /*public.cpp*/ struct A { int i; char j; float f; void foo(); }; void A::foo() {} struct B { public: int i; char j; float f; void foo(); }; void B::foo() {} int main() { return 0; }
2.
#include <iostream> using namespace std; /*private.cpp*/ struct B { private: char j; float f; public: int i; void foo(); }; void B::foo() { i = 0; j = '0'; f = 0.0; } int main() { B b; b.i = 1;//OK public //b.j = '1';Illegal,private //b.f = 1.0;Illegal,private return 0; }
3.保护(protected)
最后一种存取指定符是 protected。 protected与private基本相似,只有一点不同:继承的结构可以访问protected成员,但不能访问private成员
4.
#include <iostream> using namespace std; /*friend.cpp*/ struct X; struct Y //struct Y必须在它的成员Y :: f(X*)被声明为struct X的 //一个友元之前声明 ,但Y :: f(X*)要被声明, struct X又必须先声明 { void f(X*); }; struct X { private: int i; public: void initialize(); friend void g(X*, int); friend void Y::f(X*); friend struct Z;//friend struct Z是一个不完全的类型说明,并把整个 struct都当作一个友元。 friend void h(); }; void X::initialize() { i = 0; } void g(X* x, int i) { x->i = i; } void Y::f(X* x) { x->i = 47; } struct Z { private: int j; public: void initialize(); void g(X* x); }; void Z::initialize() { j = 99; } void Z::g(X* x) { x->i += j; } void h() { X x; x.i = 100; } int main() { X x; Z z; z.g(&x); return 0; }
5.
#include <iostream> using namespace std; /*nestfrnd.cpp*/ #include <string.h> #define SZ 20 /*struct holder包含一个整型数组和一个 p ointer,我们可以通过 pointer来存取这些整数。因为 pointer与holder紧密相连,所以有必要将它作为 struct中的一个成员。一旦 pointer被定义,它就 可以通过下面的声明来获得存取 holder的私有成员的权限: friend holder : :pointer ; 注意,这里struct关键字并不是必须的,因为编译器已经知道 pointer是什么了*/ struct holder { private: int a[SZ]; public: void initialize(); 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); }; friend holder::pointer; }; void holder::initialize() { memset(a,0,SZ*sizeof(int)); } void holder::pointer::initialize(holder* H) { h = H; p = h->a; } void holder::pointer::next() { if(p < &(h->a[SZ-1])) { p++; } } void holder::pointer::previous() { if(p > &(h->a[0])) { p--; } } void holder::pointer::top() { p = &(h->a[0]); } void holder::pointer::end() { p = &(h->a[SZ-1]); } int holder::pointer::read() { return *p; } void holder::pointer::set(int i) { *p = i; } int main() { holder h; holder::pointer hp,hp2; int i; h.initialize(); hp.initialize(&h); hp2.initialize(&h); for(i = 0;i < SZ;++i) { hp.set(i); hp.next(); } hp.top(); hp2.end(); for(i = 0;i < SZ;++i) { cout<<"hp = "<<hp.read()<<"," <<"hp2 = "<<hp2.read()<<endl; hp.next(); hp2.previous(); } return 0; }
6.
#include <iostream> using namespace std; /*class.cpp*/ struct A { private: int i,j,k; public: int f(); void g(); }; int A::f() { return i + j + k; } void A::g() { i = j = k = 0; } class B//然而class在C + +中的使用逐渐变成了一个非必要的关键字。它和 struct //的每个方面都是一样的,除了class中的成员缺省为私有的,而 struct中的 //成员缺省为public { int i,j,k; public: int f(); void g(); }; int B::f() { return i + j + k; } void B::g() { i = j = k = 0; } class X//许多人喜欢用一种更像struct的风格去创建一个类, //因为可以通过以 public开头来重载 “缺省为私有”的类行为 { public: void interface_function(); private: void private_function(); int internal_representation; }; int main() { return 0; }
7.
#include <iostream> using namespace std; /*stash.h*/ #ifndef STASH_H_ #define STASH_H_ class stash { int size; //Size of each space int quantity; //Number of storage spaces int next; //Next empty space unsigned char* storage; //storage指针是一个unsigned char*。这是 C 编译器支持的最小的存储片,尽管在某些机器 //上它可能与最大的一般大,这依赖于具体实现。 storage指向的内存从堆中分配 void inflate(int increase); /*inflate()函数使用realloc()为stash得到更大的空间块。 realloc()把已经分配而又希望重分配 的存储单元首地址作为它的第一个参数(如果这个参数为零,例如 initialize()刚刚被调用时, realloc()分配一个新块)。第二个参数是这个块新的长度,如果这个长度比原来的小,这个块 将不需要作拷贝,简单地告诉堆管理器剩下的空间是空闲的。如果这个长度比原来的大,在堆 中没有足够的相临空间,所以要分配新块,并且要拷贝内存。 assert()检查以确信这个操作成 功。(如果这个堆用光了, malloc()、 calloc()和realloc()都返回零。)*/ public: void initialize(int Size);//initialize()完成对 struct stash 的必要的设置,即设置内部变量为适当的值。最初,设置 //storage指针为零,设置size 指示器也为零,表示初始存储未被分配。 void cleanup(); //清除 int add(void* element); //add()函数在stash的下一个可用位子上插入一个元素。首先,它检查是否有可用空间,如 //果没有,它就用后面介绍的 inflate() 函数扩展存储空间。 void* fetch(int index); //fetch()首先看索引是否越界,如果没有越界,返回所希望的变量地址,地址的计算采用与 //add()中相同的方法 int count(); //返回所存储空间大小 }; #endif
8.
#include <iostream> using namespace std; /*stack.h*/ #ifndef STACK_H_ #define STACK_H_ class stack//这个嵌套 struct 称为 link,它包括指向这个表中的下一个 link 的指针和指向存放在 link 中的数据的指针,如果 next 指针是零,意味着表尾。 { struct link { void* data; link* next; void initialize(void* Data, link* Next); }*head; public: void initialize(); void push(void* Data); void* peek(); void* pop(); void cleanup();//cleanup 去除每个栈元素,并释放data 指针 }; #endif
9.
#include <iostream> using namespace std; /*减少重复编译handle.h句柄类*/ #ifndef HANDLE_H_ #define HANDLE_H_ class handle { struct cheshire;//struct cheshire;是一个没有完全指定的类型说明或类声明(一个类的定义包含类的主体) cheshire* smile; public: void initialize(); void cleanup(); int read(); void change(int); }; #endif
#include "handle.h" #include <stdlib.h> #include <assert.h> struct handle::cheshire//cheshire 是一个嵌套结构,所以它必须用范围分解符定义struct handle::cheshire { //在handle::initialize()中,为cheshire struct分配存储空间在handle::cleanup()中这些空间被释放 { int i; } void handle::initialize() { smile = (cheshire*)malloc(sizeof(cheshire)); assert(smile); smile->i = 0; } void handle::cleanup() { free(smile); } int handle::read() { return smile->i; } void handle::change(int x) { smile->i = x; }
#include "handle.h" /*客户程序员唯一能存取的就是公共的接口部分,因此,只是修改了在实现中的部分,这些 文件就不须重新编译*/ int main() { handle u; u.initialize(); u.read(); u.change(1); u.cleanup(); return 0; }
1) 创建一个类,具有public、 private 和protected数据成员和函数成员。创建该类的一个对象,看看当试图存取所有的类成员时会得到一些什么编译信息。
#include <iostream> using namespace std; class people { string phonenumber; public: int age; string name; string sex; protected: string address; }; int main() { people p; p.age = 19; p.name = "John"; p.sex = "man"; //p.address = "ShangHai"; protected错误无法访问 //p.phonenumber = "123456789";private错误无法访问 return 0; }
b.error C2248: ‘phonenumber‘ : cannot access private member declared in class ‘people‘
2) 创建一个类和一个全局friend函数来处理类的私有数据。
#include <iostream> using namespace std; struct A { int i; char c; float f; public: void initialize(); void g(); friend void h(); }; void A::initialize() { i = 0; c = '0'; f = 0.0; } void A::g() { cout<<i<<" "<<c<<" "<<f<<endl; } void h() { A a; a.i = 1; a.c = '1'; a.f = 1.0; cout<<a.i<<" "<<a.c<<" "<<a.f<<endl; } int main() { A b; b.initialize(); b.g(); h(); return 0; }
#include "handle.h" #include <stdlib.h> #include <assert.h> struct handle::cheshire//cheshire 是一个嵌套结构,所以它必须用范围分解符定义struct handle::cheshire { //在handle::initialize()中,为cheshire struct分配存储空间在handle::cleanup()中这些空间被释放 { int i; int* p; }; void handle::initialize() { smile = (cheshire*)malloc(sizeof(cheshire)); assert(smile); smile->i = 1; smile->p = NULL; } void handle::cleanup() { free(smile); } int handle::read() { return smile->i; } void handle::change(int x) { smile->i = x; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/qaz3171210/article/details/47084957