三个特征
封装
把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
继承
继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。其继承的过程,就是从一般到特殊的过程。
组合
如果鸟是可以飞的,那么鸵鸟是鸟么?鸵鸟如何继承鸟类?[美国某著名分析软件公司2005年面试题]
解析:如果所有鸟都能飞,那鸵鸟就不是鸟!回答这种问题时,不要相信自己的直觉!将直觉和合适的继承联系起来还需要一段时间。
根据题干可以得知:鸟是可以飞的。也就是说,当鸟飞行时,它的高度是大于0的。鸵鸟是鸟类(生物学上)的一种。但它的飞行高度为0(鸵鸟不能飞)。
不要把可替代性和子集相混淆。即使鸵鸟集是鸟集的一个子集(每个驼鸟集都在鸟集内),但并不意味着鸵鸟的行为能够代替鸟的行为。可替代性与行为有关,与子集没有关系。当评价一个潜在的继承关系时,重要的因素是可替代的行为,而不是子集。
答案:如果一定要让鸵鸟来继承鸟类,可以采取组合的办法,把鸟类中的可以被鸵鸟继承的函数挑选出来,这样鸵鸟就不是“a kind of”鸟了,而是“has some kind of”鸟的属性而已。代码如下:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<string> 2 #include<iostream> 3 using namespace std; 4 class bird 5 { 6 public: 7 void eat() 8 { 9 cout << "bird is eating" << endl; 10 } 11 void sleep() 12 { 13 cout << "bird is sleeping" << endl; 14 } 15 void fly(); 16 }; 17 18 class ostrich 19 { 20 public: 21 eat() 22 { 23 smallBird.eat(); 24 } 25 sleep() 26 { 27 smallBird.sleep(); 28 } 29 private: 30 bird smallBird; 31 32 }; 33 34 int main() 35 { 36 ostrich xiaoq; 37 xiaoq.eat(); 38 xiaoq.sleep(); 39 return 0; 40 }
多态
多态性指相同对象收到不同消息或不同对象收到相同消息时产生不同的实现动作。C++支持两种多态性:编译时多态性,运行时多态性。
a.编译时多态性:通过重载实现 静态 早绑定(编译时绑定)
b 运行时多态性:通过覆盖实现 动态 晚绑定(运行时绑定)
注意如果说面向对象的多态不包括重载:重载编译时就确定了,是静态,是一种语言特性,与面向对象也无关!引用一句Bruce Eckel的话:“不要犯傻,如果它不是晚邦定,它就不是多态。”
overide(覆盖)和overload(重载)
a.成员函数被重载的特征:
(1)相同的范围(在同一个类中)
(2)函数名字相同
(3)参数不同
(4)virtual 关键字可有可无
b.覆盖是指派生类函数覆盖基类函数,特征是:
(1)不同的范围(分别位于派生类与基类)
(2)函数名字相同
(3)参数相同
(4)基类函数必须有virtual 关键字
C++对象模型告诉你如何实现多态,有两个概念可以解释C++对象模型:
语言中直接支持面向对象程序设计的部分。
对于各种支持的底层实现机制。
多态是通过重载(虚函数)实现的,下一篇讲C++对象模型
动态绑定例子
1 #include <iostream> 2 using namespace std; 3 4 class Base 5 { 6 public: 7 void fun1(){ cout << "Base fun1" << endl; } 8 virtual void fun2(){ cout << "Base fun2" << endl; } 9 private: 10 int a; 11 }; 12 13 class Derive : public Base 14 { 15 public: 16 void fun1(){ cout << "Derive fun1" << endl; } 17 void fun2(){ cout << "Derive fun2" << endl; } 18 virtual void fun3(){} 19 private: 20 int b; 21 }; 22 23 int main() 24 { 25 Base b; 26 Derive d; 27 Base *p = &d; 28 p->fun1(); 29 p->fun2(); 30 31 system("pause"); 32 return 0; 33 }
输出:基类指针p在运行时发生动态绑定,fun2调用子类方法,fun1由于没有virtual,仍然调用父类方法
内存模型:
指针的虚表指向子类方法地址