C++面向对象程序设计的一些知识点(3)
摘要:多态性提供一组统一的调用接口函数,依据这些条用接口函数具体对象的不同,同一名字的函数会有不同的行为。
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)的更多相关文章
- C++面向对象程序设计的一些知识点(5)
摘要:运算符能给程序员提供一种书写数学公式的感觉,本质上运算符也是一种函数,因此有类内部运算符和全局运算符之分,通过重载,运算符的“动作”更加有针对性,编写代码更像写英文文章. 1.C++标准允许将运 ...
- C++面向对象程序设计的一些知识点(4)
摘要:累继承可以实现源代码重用,模板技术也可以达到同样的目的.模板可以分为函数模板和类模板,其共同点是允许参数类进行类型化,编译器根据程序员传递的具体类型,又把函数模板实例化为具体函数,把类模板实例化 ...
- C++面向对象程序设计的一些知识点(2)
1.C++中三种继承方式及派生类中访问控制规则 (1).C++支持的三种继承方式是public.protected.private.C++允许一个类同时以不同的方式对不同的基类加以继承. (2). 不 ...
- C++面向对象程序设计的一些知识点(1)
1.函数重载而不出错是有条件的: (1).这些函数位于同一域内,如同一类中.同一文件中. (2).这些同名函数具有不同的参数特征标(特征标是指形參的个数.类型.排列顺序等). 2.引用特性(与指针对比 ...
- 对面向对象程序设计(OOP)的认识
前言 本文主要介绍面向对象(OO)程序设计,以维基百科的解释: 面向对象程序设计(英语:Object-oriented programming,缩写:OOP),指一种程序设计范型,同时也是一种程序开发 ...
- 20162317袁逸灏 第八周实验报告:实验二 Java面向对象程序设计
20162317袁逸灏 第八周实验报告:实验二 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 ...
- 2018-2019-2 20175217 实验二《Java面向对象程序设计》实验报告
一.实验报告封面 课程:Java程序设计 班级:1752班 姓名:吴一凡 学号:20175217 指导教师:娄嘉鹏 实验日期:2019年4月15日 实验时间:--- 实验序号:实验二 实验名称:Jav ...
- 20175315 实验二《Java面向对象程序设计》实验报告
20175315 实验二<Java面向对象程序设计>实验报告 一.实验内容及步骤 1.初步掌握单元测试和TDD 单元测试 任务一:三种代码 用程序解决问题时,要学会写以下三种代码: 伪代码 ...
- 2018-2019-2 20175202实验二《Java面向对象程序设计》实验报告
2018-2019-2 20175202实验二<Java面向对象程序设计>实验报告 一.实验内容 1. 初步掌握单元测试和TDD 2. 理解并掌握面向对象三要素:封装.继承.多态 3. 初 ...
随机推荐
- mac SVN 设置代理
1. 设置代理一种方法:Finder 菜单里面 -> 前往 -> 前往文件夹 -> /Users/username/.subversion -> 编辑文件 servers 在文 ...
- java stream collector
Java Stream API进阶篇 本文github地址 上一节介绍了部分Stream常见接口方法,理解起来并不困难,但Stream的用法不止于此,本节我们将仍然以Stream为例,介绍流的规约操作 ...
- JavaWeb 路径问题
路径问题 CreateTime--2016年9月22日15:19:56 Author:Marydon 一.jsp页面 src="../demo/clazz/clazz_add.js&qu ...
- 类的专有方法(__getitem__和__setitem__)
# -*- coding: utf-8 -*- #python 27 #xiaodeng #http://www.imooc.com/code/6252 #类的专有方法(__getitem__和__s ...
- Linux 系统访问控制列表ACL
常见的文件系统的一般权限(rwx).特殊权限(SUID,SGID,STICK).隐藏权限(chattr)其实有个共性——权限是针对某一类用户设置的.而如果希望对某个指定的用户进行单独的权限控制,那么就 ...
- C#:确保绑定到同一数据源的多个控件保持同步
下面的代码示例演示如何使用 BindingSource 组件,将三个控件(两个文本框控件和一个 DataGridView 控件)绑定到 DataSet 中的同一列.该示例演示如何处理BindingCo ...
- C++开发WPF,Step by Step
示例代码 使用C++来开发WPF,主要是如何在MFC(Win32)的窗口中Host WPF的Page.下面我就做个详细的介绍. 一.创建工程, 由于MFC的Wizard会生成很多用不到的代码,所以我准 ...
- android.intent.action.MAIN, android.intent.category.LAUNCHER
android.intent.action.MAIN决定应用程序最先启动的Activity android.intent.category.LAUNCHER决定应用程序是否显示在程序列表里
- zabbix监控redis连接情况
配置zabbix客户端配置文件 vim /etc/zabbix/zabbix_agentd.conf 添加 Include=/etc/zabbix/zabbix_agentd.d/ 添加脚本对red ...
- jquery serialize对json的包装用法
jquery对象.serialize() 可以多用于表单对数据封装提交 能够收表参数,形成一个json格式字符串, 前提是:必须为每一个表单项取一个name属性 对元素 设置 name属性, 然后 ...