从一个实例看数据抽象与封装
首先使用C语言的方式来实现
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
struct Link
{
int data;
struct Link* next;
};
struct Stack
{
struct Link* head;
int size;
};
void StackInit(struct Stack* stack)//栈的初始化
{
stack->head = NULL;
stack->size = 0;
}
void StackPush(struct Stack* stack, const int data)//入栈的操作
{
struct Link* node;
node = (struct Link*)malloc(sizeof(struct Link));
assert(node != NULL);
node->data = data;
node->next = stack->head;
stack->head = node;
++stack->size;
}
//判定栈是否是空的
int StackEmpty(struct Stack* stack)
{
return (stack->size == 0);
}
int StackPop(struct Stack* stack, int* data)
{
if (StackEmpty(stack))
{
return 0;//栈为空不能够进行出栈操作,返回0
}
struct Link* tmp = stack->head;
*data = stack->head->data;
stack->head = stack->head->next;
free(tmp);
--stack->size;
return 1;
}
void StackCleanup(struct Stack* stack)
{
struct Link* tmp;
while (stack->head)
{
tmp = stack->head;
stack->head = stack->head->next;
free(tmp);
}
stack->size = 0;
}
int main(void)
{
struct Stack stack;
StackInit(&stack);
int i;
for (i = 0; i < 5; i++)
{
StackPush(&stack, i);
}
while (!StackEmpty(&stack))
{
StackPop(&stack, &i);
printf("%d", i);
}
printf("\n");
return 0;
}
使用C++语言实现
#include<iostream>
using namespace std;
class Stack//在C++中把栈封装成类,提供相应的方法
{
struct Link {
int data_;
Link* next_;
Link(int data, Link* next) :data_(data), next_(next)
{
}
};
public:
Stack() :head_(0),size_(0)
{
}
~Stack()
{
Link* tmp;
while (head_)
{
tmp = head_;
head_ = head_->next_;
delete tmp;
}
}
void Push(const int data)
{
Link* node = new Link(data, head_);
head_ = node;
++size_;
}
bool Empty()
{
return(size_ == 0);
}
bool Pop(int& data)
{
if (Empty())
{
return false;
}
Link* tmp = head_;
data = head_->data_;
head_ = head_->next_;
delete tmp;
--size_;
return true;
}
void StackInit(struct Stack* stack)
{
stack->head_ = NULL;
stack->size_ = 0;
}
private:
Link* head_;
int size_;
};
int main(void)
{
Stack stack;
int i;
for (i = 0; i < 5; i++)
{
stack.Push(i);
}
while(!stack.Empty())
{
stack.Pop( i);
cout << i << " ";
}
cout << endl;
return 0;
}
- 对比发现C++栈的初始化构造函数中实现,空间释放在析构函数中实现
- C++每个函数的调用方式都不用传递地址
- 优势:避免名称冲突 类型的扩充 数据的封装能够保护内部的数据不遭受外界的破坏
友元介绍:
友元是一种允许非类成员函数访问类的非公有成员的一种机制。
可以把一个函数指定为类的友元,也可以把整个类指定为另一个类的友元。
1.友元函数
2.友元类
友元函数在类的作用域外定义,需要在类体中进行说明。友元函数是为了提高程序的运行效率
//友元实例
#include<iostream>
#include<math.h>
using namespace std;
class Point
{
friend double Distance(const Point& p1, const Point& p2);//Point的友元函数,但不是成员函数
public:
Point(int x, int y);
private:
int x_;
int y_;
};
Point::Point(int x, int y) :x_(x), y_(y)
{
}
double Distance(const Point& p1, const Point& p2)
{
double dx = p1.x_-p2.x_;
double dy = p1.y_-p2.y_;//友元函数破坏了类的封装性
return sqrt(dx*dx+dy*dy);//友元函数的定义在类体外
}
int main(void)
{
Point p1(3, 4);
Point p2(6, 8);
cout << Distance(p1, p2) << endl;
return 0;
}
友元函数注意:
1.友元函数不是类的成员函数,在函数中访问对象的成员,必须用对象名加运算符“.”加对象成员名。但
友元函数可以访问类中所有成员,一般函数只能访问类中的公有成员。
2.友元函数不受类中的访问权限关键字的限制。(放在哪里都无所谓)
3.某类的友元函数的作用域并非该类作用域。如果该友元函数是另一个类的成员函数,则用其作用域为另一类的作用域
4.友元函数破坏了面向对象程序设计的封装性,所以友元函数如果不是必须使用,尽可能少用。
#include<iostream>
using namespace std;//电视机和遥控的例子
class Television
{
friend class TeleController;
public:
Television(int volume,int chanel):volume_(volume),chanel_(chanel)
{
}
private:
int volume_;
int chanel_;
};
class TeleController
{
public:
void VolumeUp(Television& tv)
{
tv.volume_ += 1;//不允许访问私有成员
}
void VolumeDown(Television& tv)
{
tv.volume_ -= 1;
}
void ChanelUp(Television& tv)
{
tv.chanel_ += 1;
}
void ChanelDown(Television& tv)
{
tv.chanel_ -= 1;
}
};
int main(void)
{
Television tv(1, 1);
TeleController tc;
tc.VolumeUp(tv);
return 0;
}
友元关系是单向的;友元关系是不能被传递的;友元关系不能被继承;地处理数据的函数和方法。