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

1、重载与隐藏

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

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

 #include <iostream>

 using namespace std;

 class Animal
{
public:
void walk()
{
cout << "Animal walk.\n";
}
void walk(int walkWay)
{
switch(walkWay)
{
case :
cout << "Animal jump...\n";
break;
case :
cout << "Animal fly...\n";
break;
default:
cout << "Animal scrawling...\n";
}
}
void sleep()
{
cout << "Animal sleeping..." << endl;
}
};
class Human:public Animal
{
public:
void sleep()
{
cout << "Human sleep, lying...\n";
}
}; int main()
{
Animal *pAnimal = NULL;
Animal animal;
Human human; pAnimal = &animal;
pAnimal->sleep(); pAnimal = &human;
pAnimal->sleep(); Human *pHuman = &human;
pHuman->sleep(); pHuman->walk();
pHuman->walk(); int c;
cin >> c;
return ;
}

(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函数,

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

 #include <iostream>

 using namespace std;

 class Animal
{
public:
virtual void walk()
{
cout << "Animal walk." << endl;
}
void walk(int walkWay)
{
switch(walkWay)
{
case :
cout << "Animal jump..." << endl;
break;
case :
cout << "Animal fly..." << endl;
break;
default:
cout << "Animal scraling..." << endl;
}
}
virtual void sleep()
{
cout << "Animal sleeping..." << endl;
}
private:
}; class Human:public Animal
{
public:
virtual void walk()
{
cout << "Human walk by feet." << endl;
}
virtual void sleep()
{
cout << "Human sleep, lying..." << endl;
}
virtual void talk()
{
cout << "Human talking..." << endl;
}
private:
};
int main()
{
Animal *pAnimalArray[] = {
new Animal, new Human
};
for(int i = ;i < ;i++)
{
pAnimalArray[i]->walk();
pAnimalArray[i]->sleep();
delete pAnimalArray[i];
}
int c;
cin >> c;
return ;
}

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

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

3、virtual析构函数

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

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

 #include <iostream>

 using namespace std;

 class Vehicle
{
public:
Vehicle(int power)
{
this->power = power;
}
virtual ~Vehicle()
{
cout << "deleting Vehicle sub object..." << endl;
}
public:
virtual void run()
{
cout << "Vehicle running..." << endl;
}
private:
int power;
};
class Plane:public Vehicle
{
public:
Plane(int power, double height):Vehicle(power)
{
this->height = height;
}
virtual ~Plane()
{
cout << "deleting Plane sub object..." << endl;
}
public:
void run()
{
cout << "Plane fly..." << endl;
}
private:
double height;
};
int main()
{
{
Vehicle *pVehicle = new Plane(, );
delete pVehicle;
}
int c;
cin >> c;
return ;
}

4、纯虚函数和抽象类

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

例如:

virtual void add()=0;

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

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

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

 #include <iostream>

 using namespace std;

 const double PI = 3.14159;

 class Shape
{
public:
virtual void show() = ;
virtual double area() = ;
virtual ~Shape()
{}
};
class Shape2D:public Shape
{
public:
Shape2D(double x, double y)
{
this->x = x;
this->y = y;
}
protected:
double x;
double y;
};
class Shape3D:public Shape
{
public: protected:
double x;
double y;
double z;
};
class Circle:public Shape2D
{
public:
Circle(double x, double y, double radius):Shape2D(x, y)
{
this->radius = radius;
}
virtual void show()
{
cout << "Circle center: (" << x << ", " << y << ")" << endl;
}
virtual double area()
{
return PI*radius*radius;
}
private:
double radius;
};
class Sphere:public Shape3D
{
public:
Sphere(double x, double y, double z, double radius)
{
this->x = x;
this->y = y;
this->z = z;
this->radius = radius;
}
void show()
{
cout << "Sphere center:(" << x << ", " << y << ", " << z << ")" << endl;
}
double area()
{
return PI*radius*radius*radius;
}
private:
double radius;
};
int main()
{
{
Shape *pShape = NULL;
Shape *pShapeArray[] = {
new Circle(1.0, 2.0, 3.0),
new Sphere(1.0, 2.0, 3.0, 4.0)
};
for(int i = ;i < ;i++)
{
pShapeArray[i]->show();
cout << "\t area = " << pShapeArray[i]->area() << endl;
delete pShapeArray[i];
}
}
int c;
cin >> c;
return ;
}

C++面向对象程序设计的一些知识点(3)的更多相关文章

  1. C++面向对象程序设计的一些知识点(5)

    摘要:运算符能给程序员提供一种书写数学公式的感觉,本质上运算符也是一种函数,因此有类内部运算符和全局运算符之分,通过重载,运算符的“动作”更加有针对性,编写代码更像写英文文章. 1.C++标准允许将运 ...

  2. C++面向对象程序设计的一些知识点(4)

    摘要:累继承可以实现源代码重用,模板技术也可以达到同样的目的.模板可以分为函数模板和类模板,其共同点是允许参数类进行类型化,编译器根据程序员传递的具体类型,又把函数模板实例化为具体函数,把类模板实例化 ...

  3. C++面向对象程序设计的一些知识点(2)

    1.C++中三种继承方式及派生类中访问控制规则 (1).C++支持的三种继承方式是public.protected.private.C++允许一个类同时以不同的方式对不同的基类加以继承. (2). 不 ...

  4. C++面向对象程序设计的一些知识点(1)

    1.函数重载而不出错是有条件的: (1).这些函数位于同一域内,如同一类中.同一文件中. (2).这些同名函数具有不同的参数特征标(特征标是指形參的个数.类型.排列顺序等). 2.引用特性(与指针对比 ...

  5. 对面向对象程序设计(OOP)的认识

    前言 本文主要介绍面向对象(OO)程序设计,以维基百科的解释: 面向对象程序设计(英语:Object-oriented programming,缩写:OOP),指一种程序设计范型,同时也是一种程序开发 ...

  6. 20162317袁逸灏 第八周实验报告:实验二 Java面向对象程序设计

    20162317袁逸灏 第八周实验报告:实验二 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 ...

  7. 2018-2019-2 20175217 实验二《Java面向对象程序设计》实验报告

    一.实验报告封面 课程:Java程序设计 班级:1752班 姓名:吴一凡 学号:20175217 指导教师:娄嘉鹏 实验日期:2019年4月15日 实验时间:--- 实验序号:实验二 实验名称:Jav ...

  8. 20175315 实验二《Java面向对象程序设计》实验报告

    20175315 实验二<Java面向对象程序设计>实验报告 一.实验内容及步骤 1.初步掌握单元测试和TDD 单元测试 任务一:三种代码 用程序解决问题时,要学会写以下三种代码: 伪代码 ...

  9. 2018-2019-2 20175202实验二《Java面向对象程序设计》实验报告

    2018-2019-2 20175202实验二<Java面向对象程序设计>实验报告 一.实验内容 1. 初步掌握单元测试和TDD 2. 理解并掌握面向对象三要素:封装.继承.多态 3. 初 ...

随机推荐

  1. yml 配置文件注入

    配置文件 JavaBean 自动提示 测试

  2. STS 设置 注解提示

    1.window -> Preferences

  3. phpCAS library

    The phpCAS library provides a simple API for authenticating users against a CAS server. phpCAS is co ...

  4. 【LeetCode】52. N-Queens II

    N-Queens II Follow up for N-Queens problem. Now, instead outputting board configurations, return the ...

  5. 【LeetCode】137. Single Number II (3 solutions)

    Single Number II Given an array of integers, every element appears threetimes except for one. Find t ...

  6. 一个Linux下C线程池的实现

    什么时候需要创建线程池呢?简单的说,如果一个应用需要频繁的创建和销毁线程,而任务执行的时间又非常短,这样线程创建和销毁的带来的开销就不容忽视,这时也是线程池该出场的机会了.如果线程创建和销毁时间相比任 ...

  7. gVim中重新载入当前文件

    http://club.topsage.com/thread-2251455-1-1.html有些时候当前打开的文件可能被外部程序不知不觉改变了,这个时候我们就需要重新打开这个文件,或是重读/重载一个 ...

  8. 自定义类似于listView中Item背景

    方法一. drawable/listitem_bk.xml <?xml version="1.0" encoding="utf-8" ?> < ...

  9. Windows WaveIn 录音

    设置采集音频格式 WAVEFORMATEX waveform; //采集音频的格式,结构体 waveform.wFormatTag = WAVE_FORMAT_PCM;//声音格式为PCM wavef ...

  10. codeforces#254DIV2解题报告

    今天简直大爆发啊... 吃了顿烧烤竟然这么管事. . . .. 本弱渣竟然做出来了3道,并且B题是我第一次在CF中用到算法..(曾经最多也就是贪心. . . ). 题目地址:codeforces#22 ...