数据抽象--对象与类.docx
文本预览下载声明
数据抽象--对象与类
Copyright@ 陈家骏老师
主要内容
数据抽象与封装
类和对象
对象的初始化和消亡前处理
数据抽象与封装
数据抽象
数据的使用者只需要知道对数据所能实施的操作以及这些操作之间的关系,而不必知道数据的具体表示。
数据封装
把数据表示及其操作作为一个整体来进行实现。
数据的具体表示对使用者是不可见的,对数据的访问只能通过封装体所提供的对外接口(操作)来完成。
数据抽象与封装是面向对象程序设计的基础。
例:“栈”数据的表示与操作
栈是一种由若干个具有线性次序关系的元素所构成的复合数据。对栈只能实施两种操作:
进栈(push):往栈中增加一个元素
退栈(pop):从栈中删除一个元素
上述两个操作必须在栈的同一端(称为栈顶,top)进行。后进先出(Last In First Out,简称LIFO)是栈的一个重要性质。
push(...); ...pop(...); ... ;push(x);pop(y);
x == y
栈的应用
函数调用过程中用栈保存函数的局部变量、参数、返回值以及返回地址。
把表达式的“中缀”表示转换成“后缀”表示需要用到栈:
中缀:a+b/c-d
后缀:abc/+d-
......
“栈”数据的表示与操作--非数据抽象和封装途径
定义栈数据类型
const int STACK_SIZE=100;
struct Stack
{ int top;
int buffer[STACK_SIZE];
};
直接操作栈数据
Stack st; //定义栈数据
st.top = -1; //对st进行初始化
//把12放进栈
if (st.top == STACK_SIZE-1)
{ cout “Stack is overflow.\n”; exit(-1); }
st.top++; st.buffer[st.top] = 12;
//把栈顶元素退栈并存入变量x
if (st.top == -1)
{ cout “Stack is empty.\n”; exit(-1); }
int x = st.buffer[st.top]; st.top--;
存在的问题
操作必需知道数据的表示,数据表示发生变化将影响操作
麻烦并易产生误操作,因此不安全
st.top--; //书写失误导致误操作。这里应该是st.top++;
st.buffer[st.top] = 12;
通过过程抽象操作栈数据
bool push(Stack s, int i)
{ if (s.top == STACK_SIZE-1)
{ cout “Stack is overflow.\n”;
return false;
}
else
{ s.top++; s.buffer[s.top] = i;
return true;
}
}
bool pop(Stack s, int i)
{ if (s.top == -1)
{ cout “Stack is empty.\n”;
return false;
}
else
{ i = s.buffer[s.top]; s.top--;
return true;
}
}
void init(Stack s)
{ s.top = -1;
}
Stack st; //定义栈数据
int x;
init(st); //对st进行初始化。
push(st,12); //把12放进栈。
pop(st,x); //把栈顶元素退栈并存入变量x。
存在的问题
数据类型的定义与操作的定义是分开的,二者之间没有显式的联系,push、pop在形式上与下面的函数f没有区别,函数f也能作用于st:
void f(Stack s);
f(st); //操作st之后,st可能不再是一个“栈”了!
数据表示仍然是公开的,无法防止使用者直接操作栈数据,因此也会面临直接操作栈数据所带来的问题:
st.top--;
st.buffer[st.top] = 12;
“栈”数据的表示与操作--数据抽象和封装途径
定义栈数据类型
const int STACK_SIZE=100;
class Stack
{
public:
Stack() { top = -1; }
bool push(int i);
bool pop(int i);
private:
int top;
int buffer[STACK_SIZE];
};
bool Stack::push(int i)
{ if (top == STACK_SIZE-1)
{ cout “Stack is overflow.\n”;
retur
显示全部