你所能用到的数据结构之番外篇---逆袭的面向对象(一)
对于番外篇,我深刻能明白在大多数人眼里就和电视剧的广告一样,说实话,我也不喜欢这种感觉,因为这样会让人觉得是在欺骗消费者啊~~~阿西巴~~~但是我实在发现如果不在这里对面向对象来个入门级的介绍,后面的列表类包括树,图什么实在是太难构造,或者构造出来太垃圾,所以我觉得还是应该先介绍一下面向对象,其实大部分是对自己行个方便。万事都要从最简单的开始,所以我就从0开始了。
面向对象(object-oriented),这个单词我刚学C++的时候查了不下于十次,我实在是经常记不得oriented的意思,而且这个构造出来的词实在是拗口和很难理解,我经过多年稍微能理解对象的意思,但是至今我一直无法参透面向是什么含义。object,我觉得接近的一个口头语是“东西”。和对象相关联相对应的一个概念是“类”,对象和类是一个元素和集合的关系,可以这样看,车就是一个类,小轿车也是一个类,甲壳虫就是小轿车这个类的一个对象。在我最开始学习这个的时候,有人告诉我你可以把人看做一个类,而你就是人类这个对象,我觉得这个例子很好,所以我决定用这个思想来叙写我的面向对象入门系列。
好了,我们现在要用人类作为面向对象的载体了,既然有了类这个概念,那么就要有相应的语言上的实现,就像int表示整数,float表示浮点数一样,C++既然是一种面向对象的语言,那么自然要发明创造出一种能表示这个的关键词,C++使用的是class,从这个词上也可以看出类是一种集合的概念。那我们开始定义一个“人”类了,C++的语法是class Person{}; class 是关键词,Person是要定义的类的名字,最后还有一个分号,别小看这个分号,绝对有30%的人会在编写越来越长的类中忘记这个分号,然后导致很诡异的错误半天查不出来。一个类中可以声明各种函数和变量,当声明了一个类之后,你就可以声明(定义)出这个类的对象了,有没有一种造人的感觉?哈哈,比如你想声明一个坏人,只要在main函数中写Person badman; 就像你定义int i;一样。在我的main中,我定义了一个Person的对象和一个char的独享,断点调试你可以看到下面的内容,可以看到就和局部变量c一样,同样有局部变量badman,如果你愿意,可以使用&查看这个变量的地址。
这个过程看似很简单,声明一个空类,实际上编译器做了太多的工作,这个放到后面点再说。现在先来介绍几个特殊的概念:
一、构造函数:既然是函数,那么一定是长的一个函数样,但是构造函数是一个特殊的函数,在一个类中,他没有返回类型,名字必须和类名一致,可以有参数也可以没有参数,目的是在定义对象时完成一些对象的初始化,你可以理解为准备工作。比如我们想在我们造一个人的时候都输出一句话”I am created by you“,那么我只要在class Person{};的{}里面加上public:Person(){cout<<"I am created by you."<<endl;},至于这个public什么意思,稍后面就会说明,然后运行一下:
目前的程序代码暂时是这个样子的:
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class Person 7 { 8 public: 9 Person(){cout<<"I am created by you."<<endl;} 10 };//dont't forget 11 12 13 void main() 14 { 15 Person badman; 16 17 char c; 18 cin>>c; 19 }
可以看到在我们声明一个badman的时候,会输出一行字,而这一行字正是构造函数输出的,所以你可以把构造函数是为了声明一个对象的准备工作,如果需要什么准备工作的话可以在这里进行。
二、析构函数:自然也是长的一个函数样,但是人家有名字,肯定是有特别的地方,析构函数的模式是“~”符号加上类的名字,不能有参数,为什么不能有参数,原理比较复杂,你可以思考,但是这个肯定要到介绍的差不多的时候才能写。比如Person类的析构函数是~Person(){};他的作用是当你这个对象脱离作用域的时候(比如主函数结束)的时候做一些清理工作,怎么来看到他的效果呢?我们也在函数体中输出一句话“I am destoryed.” 执行一下,输入一个字符退出,咦,似乎有什么闪了一下,怎么查看效果呢?我们在main的最后一个花括号后面设置一个断点,点击执行,输入一个字符退出,好,现在程序到了断点的地方,再按一下F10,不是分开按F和10,再打开输出窗口,会看到下面的输出结果:
又输出了一句话,我第一次看到这个的时候真心感到神奇,为什么会输出这样一句话,程序离理论上说已经结束了,cin后面没有语句了,这就是构造函数的作用,可以理解为在结束的时候帮你擦屁股的人,唉真是伟大啊,所以在这里你可以做任何清理工作,比如回收内存等等。
除了这两个特殊的函数,还有三个特殊的关键字,public,protected,private,这三个关键字是C++类的访问控制符,为了达到安全和封装两个目的,封装也是C++之一,就像一个人一样,你的名字在大多数情况下是公开的,你的私人小金库是秘密的,你的银行卡密码是受保护的,所谓受保护的就是在外面别人是不知道的,但是某些和你有特殊关系的人是可以知道的,比如你的老婆。对于一个类,什么叫公开呢?所谓的公开就是在外部声明的对象可以访问这些东西,无论是函数还是变量,比如我想声明一个公开的变量Name,一个受保护的变量bankPassword和一个私密的变量privateMoney,然后利用badman这个对象去尝试访问这三个变量,在C++中采用的"."或者"->"(这个符号是用在声明了一个指向对象的指针上)来访问类中定义的变量,现在的代码如下所示:
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class Person 7 { 8 protected: 9 string bankPassowrd; 10 private: 11 int priavteMoney; 12 public: 13 string Name; 14 Person(){cout<<"I am created by you."<<endl;} 15 ~Person(){cout<<"I am destroyed."<<endl;} 16 };//dont't forget 17 18 19 void main() 20 { 21 Person badman; 22 badman.Name; 23 badman.bankPassowrd; 24 badman.priavteMoney; 25 char c; 26 cin>
这三个的排列顺序是无所谓的,我们执行一下会发现报错:
报错提示有两个变量无法访问,原因就是他们的控制符不是公开的,再说一下,"公开"什么的都是相对外部来说的,如果在一个类的内部是没有这些限制的,所有的都能自由访问,这些控制符使得类的设计者可以自由灵活的控制外部使用人员可以使用什么和不可以使用什么,这样在类的使用者看起来类就像一个黑盒子,也可以让类的使用者不用去关心这一切都是怎么实现的。就像一个电视机遥控器,你只管按数字,不用管里面的电路板,这就是封装的概念。
那么如果我们申明一个类的时候不加控制符直接声明一个变量或者函数会怎么样呢?你可以先猜猜再试试。