1、面向对象的三大特点:
(1)封装:把客观事物封装成抽象类,达到“属性和方法的集和性”和“信息隐蔽性”;
(2)继承:派生类可以继承基类的属性和方法;
(3)多态:主要体现在函数覆盖上,覆盖是针对虚函数。
C++代码练习:
1 #include <stdlib.h> 2 #include <windows.h> 3 4 #pragma pack(1) 5 6 ////////////////////////////////////////////////////////////////////////// 7 // 面向对象三大特征之一:封装 8 // 方法和属性包装成一个整体,并且具有信息隐蔽性 9 class Desk 10 { 11 private: 12 int height; 13 public: 14 void ToString() // 普通函数 15 { 16 printf("I'm nothing but a Desk ! "); 17 } 18 virtual void SaySomething() // 虚函数,派生类可以选择性的重写 19 { 20 printf("Hello, I'm a Desk ! "); 21 }; 22 23 // 纯虚函数,派生类必须重写,否则不能被实例化,类似于Java中的接口,Java中的接口函数必须实现,否则无法编译 24 // 有纯虚函数的类叫做抽象类,抽象类无法实例化 25 // 如果派生类没有重写纯虚函数的话,派生类也是抽象类 26 virtual void DoSomething() = 0; 27 }; 28 29 ////////////////////////////////////////////////////////////////////////// 30 // 面向对象三大特征之二:继承 31 // 派生类能够继承父类的属性和方法 32 class SmallDesk : public Desk 33 { 34 public: 35 void ToString() // 重写普通函数 36 { 37 printf("I'm not only a Desk. I'm a SmallDesk ! "); 38 } 39 void SaySomething() // 选择重写了虚函数,可以被调用 40 { 41 printf("Hi, I'm a SmallDesk ! "); 42 }; 43 void DoSomething() // 必须重写纯虚函数 44 { 45 printf("A SmallDesk did something! "); 46 Sleep(100); 47 } 48 }; 49 50 class BigDesk : public Desk 51 { 52 public: 53 void ToString() // 重写普通函数 54 { 55 printf("I'm not only a Desk. I'm a BigDesk ! "); 56 } 57 // 此处没有重写虚函数,会调用对应的基类函数 58 59 // 但是必须重写下面的纯虚函数,否则会在声明对象的时候产生错误: 60 // error C2259: “BigDesk”: 不能实例化抽象类 61 void DoSomething() 62 { 63 printf("A BigDesk did something ! "); 64 Sleep(100); 65 } 66 }; 67 68 // Desk是抽象类,因此不能定义函数: void VisitDesk(Desk desk) 69 void VisitDesk(Desk& rfr); 70 void VisitDesk(Desk* ptr); 71 72 int main() 73 { 74 75 SmallDesk sd; 76 BigDesk bd; 77 sd.ToString(); // 重写了基类的函数,于是调用了派生类的函数 78 sd.SaySomething(); // 重写了基类的虚函数,于是调用派生类的函数 79 sd.DoSomething(); // 调用派生类的函数 80 81 bd.ToString(); // 重写了基类的函数,于是调用了派生类的函数 82 bd.SaySomething(); // 没有重写基类的虚函数,调用基类的虚函数 83 bd.DoSomething(); // 调用派生类的函数 84 85 ////////////////////////////////////////////////////////////////////////// 86 // 面向对象的三大特征之三:多态 87 // 真正和多态相关联的,是函数的重写(即:覆盖),尤其是虚函数的重写,因为非虚函数的重写,基类指针无法调用 88 89 // 1、通过指针完成多态 90 // 如果采用默认或private方式继承,下面一句会产出错误: 91 // error C2243: “类型转换”: 从“SmallDesk *”到“Desk *”的转换存在,但无法访问 92 Desk* ptr = &sd; 93 ptr->ToString(); // 调用基类的函数,即使派生类中已经重写 94 ptr->SaySomething(); // 调用派生类的函数,因为派生类中重写了该函数 95 ptr->DoSomething(); // 调用派生类的函数,派生类必须重写此函数,否则无法实例化 96 97 // 多态真正的用途是在一个方法中,不需要知道派生类是什么,只需传入基类参数,即可访问形形色色的派生类 98 VisitDesk(&bd); 99 100 // 2、通过引用完成多态 101 // 如果采用默认或private方式继承,下面一句会产出错误: 102 // error C2243: “类型转换”: 从“SmallDesk *”到“Desk &”的转换存在,但无法访问 103 Desk& rfr = bd; 104 rfr.ToString(); // 调用基类的函数,即使派生类中已经重写 105 rfr.SaySomething(); // 调用基类的函数,因为派生类中没有重写 106 rfr.DoSomething(); // 调用派生类的函数,派生类必须重写此函数,否则无法实例化 107 108 // 多态真正的用途是在一个方法中,不需要知道派生类是什么,只需传入基类参数,即可访问形形色色的派生类 109 VisitDesk((Desk&)sd); 110 111 ////////////////////////////////////////////////////////////////////////// 112 // 其它 113 printf("sizeof(Desk) = %d ", sizeof(Desk)); // 有虚函数的空类的大小为4字节,再加上一个整型变量,共8字节 114 system("pause"); 115 return 0; 116 } 117 118 void VisitDesk(Desk& rfr) 119 { 120 rfr.ToString(); // 调用基类的函数,即使派生类中有没有重写,也就是说,普通函数没有多态的效果 121 rfr.SaySomething(); // 首先看派生类中有没有重写,如果没有,则调用基类函数 122 rfr.DoSomething(); // 调用派生类的函数,派生类必须重写此函数,否则无法实例化 123 } 124 125 void VisitDesk(Desk* ptr) 126 { 127 ptr->ToString(); // 调用基类的函数,不管派生类中有没有重写,也就是说,普通函数没有多态的效果 128 ptr->SaySomething(); // 首先看派生类中有没有重写,如果没有,则调用基类函数 129 ptr->DoSomething(); // 调用派生类的函数,派生类必须重写此函数,否则无法实例化 130 }
输出结果:
I'm not only a Desk. I'm a SmallDesk ! Hi, I'm a SmallDesk ! A SmallDesk did something! I'm not only a Desk. I'm a BigDesk ! Hello, I'm a Desk ! A BigDesk did something ! I'm nothing but a Desk ! Hi, I'm a SmallDesk ! A SmallDesk did something! I'm nothing but a Desk ! Hello, I'm a Desk ! A BigDesk did something ! I'm nothing but a Desk ! Hello, I'm a Desk ! A BigDesk did something ! I'm nothing but a Desk ! Hi, I'm a SmallDesk ! A SmallDesk did something! sizeof(Desk) = 8 请按任意键继续. . .