博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++面向对象程序设计的一些知识点(3)
阅读量:6264 次
发布时间:2019-06-22

本文共 6745 字,大约阅读时间需要 22 分钟。

摘要:多态性提供一组统一的调用接口函数,依据这些条用接口函数具体对象的不同,同一名字的函数会有不同的行为。

1、重载与隐藏

(1)、对同一作用域中的同名函数,如果它们的函数特征标不同,那么它们就形成一种重载关系。

(2)、基类与派生类中非虚同名函数,不管它们的参数特征标是否相同,它们都形成隐藏关系,即派生类对象隐藏基类中的同名函数。

1 #include 
2 3 using namespace std; 4 5 class Animal 6 { 7 public: 8 void walk() 9 {10 cout << "Animal walk.\n";11 }12 void walk(int walkWay)13 {14 switch(walkWay)15 {16 case 0:17 cout << "Animal jump...\n";18 break;19 case 1:20 cout << "Animal fly...\n";21 break;22 default:23 cout << "Animal scrawling...\n";24 }25 }26 void sleep()27 {28 cout << "Animal sleeping..." << endl;29 }30 };31 class Human:public Animal32 {33 public:34 void sleep()35 {36 cout << "Human sleep, lying...\n";37 }38 };39 40 int main()41 {42 Animal *pAnimal = NULL;43 Animal animal;44 Human human;45 46 pAnimal = &animal;47 pAnimal->sleep();48 49 pAnimal = &human;50 pAnimal->sleep();51 52 Human *pHuman = &human;53 pHuman->sleep();54 55 pHuman->walk(1);56 pHuman->walk();57 58 int c;59 cin >> c;60 return 0;61 }
View Code

(3)、在此示例代码中,同一类中的成员函数walk()与walk(int walkWay)形成重载。

(4)、分别位于基类Animal与派生类Human中的成员函数sleep()形成隐藏关系,即派生类Human的sleep()隐藏了基类的Animal中成员函数sleep()。

(5)、依据基类和派生类的兼容性原则,可以将派生类Human对象human的地址赋值给基类Animal的指针pAnimal。不过这时pAnimal指向的函数永远是基类的成员函数。

(6)、由于派生类Human的sleep()隐藏了基类Animal中的成员函数sleep(),所以pHuman->sleep()调用派生类Human的sleep()。

(7)、注意:基类指针永远无法调用该基类派生的同名函数。

2、多态性

(1)、虚函数:若类的成员函数用关键字virtual修饰,则称该函数为该类的虚函数,其声明语法如下:

virtual 返回值类型 函数名(形参列表);

例如:

class Animal

{

public:

  virtual void sleep()

  {

    cout << "Animal sleep." << endl;

  }

};

(2)、函数覆盖:若位于基类和派生类中的两个同名虚函数的声明完全相同(包括返回值类型),则这样的两个函数形成覆盖关系。

例如:

class Pet

{

  virtual void sleep()

  {

    cout << "Pet sleep." << endl;

  }

};

class Fish:public Pet

{

  virtual viod sleep()

  {  

    cout << "Fish sleep." << endl;

  }

};

(3)、多态性实现步骤:

1)、在基类中说明成员函数为virtual函数,在直接派生类或间接派生类中根据实际应用重写这些virtual函数。

2)、在直接派生类或间接派生类中覆盖那些virtual函数,它们的声明必须和基类对应的虚函数声明严格一致。

3)、声明基类指针或者基类引用;给基类指针或者引用赋值,此时对象地址既可以是基类对象地址,也可以是派生类对象地址;有指针或者引用去调用相应的virtual函数,

根据对象的不同,真正被调用的函数可以是基类同名函数,也可以是派生类同名函数。

1 #include 
2 3 using namespace std; 4 5 class Animal 6 { 7 public: 8 virtual void walk() 9 {10 cout << "Animal walk." << endl;11 }12 void walk(int walkWay)13 {14 switch(walkWay)15 {16 case 0:17 cout << "Animal jump..." << endl;18 break;19 case 1:20 cout << "Animal fly..." << endl;21 break;22 default:23 cout << "Animal scraling..." << endl;24 }25 }26 virtual void sleep()27 {28 cout << "Animal sleeping..." << endl;29 }30 private:31 };32 33 class Human:public Animal34 {35 public:36 virtual void walk()37 {38 cout << "Human walk by feet." << endl;39 }40 virtual void sleep()41 {42 cout << "Human sleep, lying..." << endl;43 }44 virtual void talk()45 {46 cout << "Human talking..." << endl;47 }48 private:49 };50 int main()51 {52 Animal *pAnimalArray[] = {53 new Animal, new Human54 };55 for(int i = 0;i < 2;i++)56 {57 pAnimalArray[i]->walk();58 pAnimalArray[i]->sleep();59 delete pAnimalArray[i];60 }61 int c;62 cin >> c;63 return 0;64 }
View Code

(4)、注意:若在类中只声明虚函数原型,则在类外部定义虚函数时不必加virtual关键字;若派生类覆盖基类某个虚函数,则派生类中对应的虚函数可以加virtual也可以

加;一个虚函数,他在直接派生类和间接派生类中依然保持虚函数的特性;虚函数必须是成员函数;只有通过指针或引用方式访问虚函数,才能获得虚函数的动态特性。

 3、virtual析构函数

(1)、通常,我们会才用基类指针或引用来指向派生类对象,此时,使用delete释放堆中的对象时,只会释放其基类子对象部分而不会自动释放派生类子对象部分。解决

办法是把基类和派生类的析构函数都声明为virtual类型。

1 #include 
2 3 using namespace std; 4 5 class Vehicle 6 { 7 public: 8 Vehicle(int power) 9 {10 this->power = power;11 }12 virtual ~Vehicle()13 {14 cout << "deleting Vehicle sub object..." << endl;15 }16 public:17 virtual void run()18 {19 cout << "Vehicle running..." << endl;20 }21 private:22 int power;23 };24 class Plane:public Vehicle25 {26 public:27 Plane(int power, double height):Vehicle(power)28 {29 this->height = height;30 }31 virtual ~Plane()32 {33 cout << "deleting Plane sub object..." << endl;34 }35 public:36 void run()37 {38 cout << "Plane fly..." << endl;39 }40 private:41 double height;42 };43 int main()44 {45 {46 Vehicle *pVehicle = new Plane(30, 3005);47 delete pVehicle;48 }49 int c;50 cin >> c;51 return 0;52 }
View Code

4、纯虚函数和抽象类

(1)、纯虚函数:类中的virtual成员函数,如果没有实现体(即定义实现体为0),则称这样的函数为纯虚函数。

例如:

virtual void add()=0;

(2)、抽象类:当一个类含有一个或者多个纯虚函数时,称这样的类为抽象类。

注意:抽象类的纯虚函数可以是我们后续加入的或者从基类继承的,当然如果一个类继承一个或多个纯虚函数之后再一一实现这些纯虚函数,那么这样的类不再是抽象类;

抽象类不能用于创建对象,但允许定义抽象对象指针。

1 #include 
2 3 using namespace std; 4 5 const double PI = 3.14159; 6 7 class Shape 8 { 9 public:10 virtual void show() = 0;11 virtual double area() = 0;12 virtual ~Shape()13 {}14 };15 class Shape2D:public Shape16 {17 public:18 Shape2D(double x, double y)19 {20 this->x = x;21 this->y = y;22 }23 protected:24 double x;25 double y;26 };27 class Shape3D:public Shape28 {29 public:30 31 protected:32 double x;33 double y;34 double z;35 };36 class Circle:public Shape2D37 {38 public:39 Circle(double x, double y, double radius):Shape2D(x, y)40 {41 this->radius = radius;42 }43 virtual void show()44 {45 cout << "Circle center: (" << x << ", " << y << ")" << endl;46 }47 virtual double area()48 {49 return PI*radius*radius;50 }51 private:52 double radius;53 };54 class Sphere:public Shape3D55 {56 public:57 Sphere(double x, double y, double z, double radius)58 {59 this->x = x;60 this->y = y;61 this->z = z;62 this->radius = radius;63 }64 void show()65 {66 cout << "Sphere center:(" << x << ", " << y << ", " << z << ")" << endl;67 }68 double area()69 {70 return PI*radius*radius*radius;71 }72 private:73 double radius;74 };75 int main()76 {77 {78 Shape *pShape = NULL;79 Shape *pShapeArray[] = {80 new Circle(1.0, 2.0, 3.0),81 new Sphere(1.0, 2.0, 3.0, 4.0)82 };83 for(int i = 0;i < 2;i++)84 {85 pShapeArray[i]->show();86 cout << "\t area = " << pShapeArray[i]->area() << endl;87 delete pShapeArray[i];88 }89 }90 int c;91 cin >> c;92 return 0;93 }
View Code

 

转载地址:http://rmzpa.baihongyu.com/

你可能感兴趣的文章
VS2017桌面应用程序打包成.msi或者.exe
查看>>
Linux进程调度原理【转】
查看>>
大白话说Java反射:入门、使用、原理
查看>>
Dockerfile 中的 multi-stage(多阶段构建)
查看>>
nodejs中的cron
查看>>
Failed to import package with error: Couldn't decompress package的解决方案
查看>>
[日常] Go语言圣经-WEB服务与习题
查看>>
javax.websocket.Session的一个close异常记录
查看>>
I2C 12864OLED的工作机制
查看>>
在Unity场景中更改天空盒的步骤
查看>>
hibernate联合主键注解方式
查看>>
JNotify的监测文件变化的简单测试例子
查看>>
ALINX公众号
查看>>
Oracle 分区表的新增、修改、删除、合并。普通表转分区表方法
查看>>
RedisHelper帮助类
查看>>
js进阶 10-1 JQuery是什么
查看>>
Hadoop生态圈-Flume的组件之自定义拦截器(interceptor)
查看>>
orcale查询表之间的关联关系
查看>>
关于pythoh面向过程开发人员三步转面向对象的补充,再加一步,四步走战略。转面向对象也可以有固定公式。...
查看>>
SVN设置必须锁定
查看>>