面向对象(objected-oriented,或者说理解为面向物体\实体 更合适一些),重要特点就是:封装、抽象、多态、继承
在本篇中,主要提及的是封装(Encapsulation)。而封装提供给我们的不只是更加结构化、模块化的程序设计,还有一个最重要的特性:数据隐藏。
一、访问标号:public-private-protected
简单的来说,访问标号的用处就相当于为各个类成员添加一个权限。好比linux系统下的文件权限一样,可以对不同的访问者、用户组给予不同权限。
类成员的访问者有三个:自身成员访问、类的对象访问、派生类访问。很好理解——
自身成员访问:
因为是自己的,所以相当于root权限。不会对自己隐藏自己的东西,哪怕是private。类比: 不管你怎么隐藏硬盘中的文件,硬盘自己都知道它在哪
类的对象访问:
——什么是对象?你不会做cpu,不会写操作系统,但这并不妨碍你能使用电脑。电脑就是一个对象,你能够使用该对象提供的接口-interface。
对象可以看做是用class封装后生产出的产品。生产的成品会使用自己内部的构造,而你只是负责使用的,所以你不必知道它是怎么使用的。
另一方面生产者往往也并不想给你公开这个东西的内部结构,一是怕你随便拆拆坏了--[数据保护],二是为了保护自己的专利--[数据隐藏]。
所以,类把源码和成品分开,并添加权限private\pubic做为区分。
派生类访问:
虽然同样是LINUX操作系统,但是我不仅可以在PC上使用它,我加一个外壳,把它做成Android,还可以在手机上使用它。
这里,Android就是Linux的一个派生类,而作为操作系统,Android显然不能不关心Linux是怎么工作的,所以对于Android用到的基于Linux的功能,Android必须能够有权限看到这部分的工作方式——protected。(当然作为用产品的人,我们还是不必知道这个东西里面究竟是怎么回事,对于对象来说protected也是加密的)。
而之所以开辟出这么一个级别,是因为面向对象的特性:多态、继承。Linux能够做桌面操作系统Ubuntu,还能做嵌入式操作系统Raspbian,更能来做手机操作系统Android。(其实WIndows也很厉害的,还能做ATM。。。)他们属于linux的分支(继承),但又各自拥有不同的新特性(多态)
说了这么过,访问标号的问题反而好理解了:
public——公开展示,任何人都可以访问
private——隐私内容,只有类成员函数可以访问。(不过friend友元函数也是可以的,可以理解为至交好友之类的。这里先不讨论)
protected——类成员函数可以访问、派生类可以访问基类的protected、对象不可访问。
二、public-protected-private的继承
[1] 继承的使用:公用继承、受保护继承、私有继承
class Child : public/protected/private Father {
};
[2]多态,继承后的变化
[3] 基类行为:总裁并不那么负责任
三、提供更丰富的函数接口
1、实现调用构造函数的同时,维护vector<Node*> sortedNode,使之存放排序后的节点
void* getAllNode(Node *a) {sortedTree.push_back(a);return NULL;}
作为维护vector的函数。
/* inorder visit BST */
void BST::inorderBST()
{
if(head==NULL)
return;
inorderBST(head->left);
this->getAllNode(head);
inorderBST(head->right);
std::cout<<std::endl;
}
void BST::inorderBST(Node* head)
{
if(head==NULL)
return;
inorderBST(head->left);
this->getAllNode(head);
inorderBST(head->right);
}
这里重载了inroderBST,原因在2中有分析。
BST::BST(const vector<int>&num)
{
if(num.size()==0){
std::cout<<"Create Tree Failed, NULL Input!\n";
return;
}
Node *put = new Node(num[0]);
//fun = &getAllNode;
sortedTree.push_back(put);
head = put;
for(unsigned int i=1;i<num.size();i++)
{
put = new Node(num[i]);
insertNode(*head,*put);
//printNode(put);
}
inorderBST();
}
/* ----- */
2、提供拥有函数接口的inorderBST函数
void inorderBST(void*(*)(Node*,void*),void*);
void BST::inorderBST(void*(*)(Node*,void*) fun,void* argument)
{
if(head==NULL)
return;
inorderBST(head->left,fun,argument);
fun(head,argument);
inorderBST(head->right,fun,argument);
}
void BST::inorderBST(Node* head,<span style="font-family: Arial, Helvetica, sans-serif;">void*(*)(Node*,void*)</span> fun,void* argument)
{
if(head==NULL)
return;
inorderBST(head->left,fun,argument);
fun(head,argument);
inorderBST(head->right,fun,argument);
}
上面就是我们对于inorderBST函数的实现。
第二个函数作为内置调用的函数,标记为private。只希望内部调用,而希望对object隐藏。
至此,我们的class变成了这样——
class BST {
private:
inline void insertNode(Node&,Node&);
void inorderBST(Node* head);
void _deleteBST(Node* head);
//BSTFUN fun;
void inorderBST();
void inorderBST(Node*,<span style="font-family: Arial, Helvetica, sans-serif;">void*(*)(Node*,void*)</span>,void*);
void* getAllNode(Node *a) {sortedTree.push_back(a);return NULL;}
public:
Node* head;
vector<Node*> sortedTree;
void inorderBST(<span style="font-family: Arial, Helvetica, sans-serif;">void*(*)(Node*,void*)</span>,void*);
BST():head(NULL){};
BST(const vector<int>&);
};
3、演示带有函数参数的inorderBST接口的使用:
void* printfnode(Node* a,void* arg)
{
std::cout<<a->val<<"==";
return NULL;
}
struct get {
vector<int> left;
};
void* getNodeVal(Node*a, void* arg)
{
((get*)arg)->left.push_back(a->val);
return NULL;
}
/* == make sure destructor work == */
int main()
{
int a[7] = {3,1,8,2,6,7,5};
vector<int> num(a,a+7);
BST tree1(num);
tree1.inorderBST(printfnode,NULL);
get tmp;
tree1.inorderBST(getNodeVal,(void*)&tmp);
return 0;
}