Chapter 5. Hiding the implementation
一、友元
//friend.cpp
// public, private, protected
// friends
struct X;
struct Y {
void f(X*);
};
struct X {
private:
int i;
public:
void initialize();
friend void Y::f(X*); // struct member friend
friend struct Z; // Entire struct is a friend
friend void g(X*, int); // Global friend
friend void h();
};
void X::initialize()
{
i = 0;
}
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 g(X *x, int i)
{
x->i = i;
}
void h()
{
X x;
x.i = 100;
}
int main()
{
X x;
Z z;
z.g(&x);
}
此代码示范了friend友元的用途,声明友元的类在告诉大家,此友元可以访问我的私有成员。
* 从struct X的定义可以看出,在public区域定义了四种友元,他们都可以试图访问修改私
有成员i,当然也包括自己的成员函数。
全局友元函数 global friend
在函数体内,可以任意修改struct X类对象的成员i。
类成员作为友元 struct member friend
可以更改传递的X*参数。
整个类作为友元 entire struct
这样此类的所有成员函数,都拥有友元性质。
二、嵌套的友元
//nested_friend.cpp
#include <iostream>
#include <cstring>
using namespace std;
const int sz = 20;
struct Holder {
private:
int a[sz];
public:
void initialize();
struct Pointer;
friend struct Pointer;
struct Pointer { // nested struct friend
private:
Holder *h;
int *p;
public:
void initialize(Holder *h);
void next();
void previous();
void top();
void end();
int read();
void set(int i);
};
};
// type class::nested_class::variable;
void Holder::initialize()
{
memset(a, 0, sz * sizeof(int));
}
void Holder::Pointer::initialize(Holder *rv)
{
h = rv;
p = rv->a; // access private member of super class
}
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();
}
}
/* result:
hp = 0, hp2 = 19
hp = 1, hp2 = 18
hp = 2, hp2 = 17
hp = 3, hp2 = 16
hp = 4, hp2 = 15
hp = 5, hp2 = 14
hp = 6, hp2 = 13
hp = 7, hp2 = 12
hp = 8, hp2 = 11
hp = 9, hp2 = 10
hp = 10, hp2 = 9
hp = 11, hp2 = 8
hp = 12, hp2 = 7
hp = 13, hp2 = 6
hp = 14, hp2 = 5
hp = 15, hp2 = 4
hp = 16, hp2 = 3
hp = 17, hp2 = 2
hp = 18, hp2 = 1
hp = 19, hp2 = 0
*/
这里的Holder类中又包含Pointer类定义,这是个嵌套类。例子在展示子类作为友元时的用
途。
在这里定义了Holder类对象h,和子类Pointer对象hp,hp2,他们包含有h的指针,和父类私
有成员a的位置。作为友元类,hp和hp2可以访问、修改父类对象h的私有成员int a[];
三、初识构造函数和析构函数
//constructor.cpp
#include <iostream>
using namespace std;
class Tree {
int height;
public:
Tree(int initialHeight);
~Tree();
void grow(int years);
void printsize();
};
Tree::Tree(int initialHeight)
{
height = initialHeight;
}
Tree::~Tree()
{
cout << "inside tree destructor " << endl;
printsize();
}
void Tree::grow(int years)
{
height += years;
}
void Tree::printsize()
{
cout << "Tree height is " << height << endl;
}
int main()
{
cout << "before opening brace " << endl;
{
Tree t(12); //constructor called
cout << "after Tree creation" << endl;
t.printsize();
t.grow(4);
cout << "before closing brace" << endl;
//destructor called(endline of t)
}
cout << "after closing brace " << endl;
}
/* result:
before opening brace
after Tree creation
Tree height is 12
before closing brace
inside tree destructor
Tree height is 16
after closing brace
*/
例子展示了constructor和destructor的性能。
* constructor在建立对象的时候,由编译器插入语句,完成初始化行为,在对象生命期内
只执行一次。
* destructor相反,在注销对象的时候执行。
* 代码中使用了{}圈定对象Tree T的生命域,它在`}'之后被注销。
下面讲述constructor一个特性。
//nojump.cpp
#include <iostream>
using namespace std;
class X {
public:
X();
};
X::X() {}
void f(int i)
{
if (i < 10) {
// crosses initialization of `X x1'
// goto jump1;
}
X x1;
jump1:
switch (i) {
case 1:
X x2;
// crosses initialization of `X x3'
break;
// case 2:
X x3;
break;
}
}
int main()
{
f(9);
f(11);
}
这是一个诡异的例子,首字符注释段取消注释之后,编译器将报错: `cross
initialization'。GCC将不允许goto,case语句等,来跳过任何对象的定义(初始化)阶段。
四、定义stack
//stack.h
#ifndef _STACK_H
#define _STACK_H
class stack {
struct linklist {
void *data;
linklist *next;
linklist(void *dat, linklist* nxt);
~linklist();
}* head;
public:
stack();
~stack();
void push(void *data);
void *peek();
void *pop();
};
#endif // STACK_H
//stack.cpp
#include "stack.h"
stack::linklist::linklist(void *dat, linklist *nxt)
{
data = dat;
next = nxt;
}
stack::linklist::~linklist() {}
stack::stack()
{
head = 0;
}
void * stack::peek()
{
if (head != 0)
return head->data;
else
return 0;
}
void stack::push(void *dat)
{
head = new linklist(dat, head);
}
void * stack::pop()
{
if (head == 0)
return 0;
void *result = head->data;
linklist *oldHead = head;
head = head->next;
delete oldHead;
return result;
}
stack::~stack()
{
if (head != 0)
return;
}
//stacktest.cpp
#include "stack.h"
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
// requireArgs(argc, 1);
ifstream in(argv[1]);
if(in == 0)
return -1;
// assure(in, argv[1]);
stack textlines;
string line;
while (getline(in, line))
textlines.push(new string(line));
string *s;
while ((s = (string *)textlines.pop()) != 0) {
cout << *s << endl;
delete s;
}
}
/* 执行命令 ./a.out Makefile
* 将按行逆序打印Makefile内容。
*/
stack.h,stack.cpp,stacktest.cpp是链表式堆栈的实现。
* linklist是节点数据结构的实现,他是stack数据结构的成员。
* 无论对于父子类对象,他们都会有自己的构造函数和析构函数。
* push函数非常漂亮!
* 使用new 和 delete,来分配堆区空间,这会使得C++代码更加优雅。
没有评论:
发表评论