一、基类指针、派生类指针

父类指针可以new一个子类对象

二、虚函数

有没有一个解决方法,使我们只定义一个对象指针,就可以调用父类,以及各个子类的同名函数?

有解决方案,这个对象指针必须是一个父类类型,我们如果想通过一个父类指针调用父类、子类中的同名函数的话,这个函数是有要求的;

在父类中,eat函数声明之前必须要加virtual声明eat()函数为虚函数。

一旦某个函数被声明为虚函数,那么所有派生类(子类)中eat()函数都是虚函数。

为了避免你在子类中写错虚函数,在C++11中,你可以在函数声明中增加一个override关键字,这个关键字用在子类中,而且是虚函数专用。

override就是用来说明派生类中的虚函数,你用了这个关键字之后,编译器就会认为你这个eat是覆盖了父类中的同名函数(只有虚函数才存在子类可以覆盖父类中同名函数的问题),那么编译器就会在父类中找同名的虚函数,如果没找到,编译器就会报错,如果你不小心在子类中把虚函数写错了名字,写错了参数,编译器能够帮你进行纠错。

final也是虚函数专用,用在父类中,如果我们在父类的函数声明中加了final,那么任何尝试覆盖在函数的操作都会引发错误。

调用虚函数执行的是“动态绑定”。动态表示我们程序运行的时候才能知道调用了那个子类的中的eat()虚函数。

动态的绑定到Men上去,还是Women上去,取决于new的Men还是Women;

动态绑定:运行的时候才决定你的phuman对象绑定到那个eat()函数上运行。

三、多态性

多态性只是针对虚函数来说的;

多态性:体现在具有继承关系的父类和子类之间,子类重新定义(重写)父类的成员函数eat(),同时父类把这个eat()函数声明为virtual虚函数;

通过父类的指针,只有到了程序运行时期,找到动态绑定到父类指针上的对象,这个对象有可能是某个子类对象,也可能是父类对象;

然后系统内部实际上是要查找一个虚函数表,找到函数eat()的入口地址,从而调用父类或子类的eat()函数,这就是运行时的多态性。

四、纯虚函数

纯虚函数是在基类中声明的函数,但是他在基类中没有定义,但是要求任何派生类都要定义该虚函数自己的实现方法;

基类中实现纯虚函数的方法使在函数原型后面增加 =0;

一旦一个类中又纯虚函数,那么你就不能生成这个类的对象了;

抽象类不能用来生成对象,主要目的是用来同意管理子类对象;

(1)纯虚函数的类叫做抽象类,不能用来生成该类对象,主要用于当做基类来生成子类用的;

(2)子类必须要实现该基类中定义纯虚函数;

五、基类的析构函数一般写成虚函数(虚析构函数)

用基类指针new子类的对象,在delete的时候,系统不会调用派生类的析构函数,存在问题;

解决方案:将基类的析构函数声明为虚析构函数;

在public继承中,基类对派生类及其对象的操作,只能影响那些从基类继承下来的成员,如果想要用基类对非继承的成员进行操作,则要把基类的这个函数定义为虚函数,析构函数也为虚函数,基类中的析构函数的虚属性也会被派生类继承,即派生类的析构函数也为虚函数。

Human这个类中的析构函数就要声明为virtual的,也就是说C++11中为了获得运行时多态,所调用的成员必须是virtual的。

如果一个类想要做基类,我们必须将类的析构函数声明为virtual虚函数;

只要基类中的析构函数为虚函数,就能保证我们delete基类指针时能够运行正确,不会出现内存泄漏。

虚函数会增加内存开销,类里面定义虚函数,编译器就会给这个类增加虚函数表,在这个表里存放虚函数的指针。

本节案例:

// Human.h
// 头文件防卫式声明
#ifndef __HUMAN__
#define __HUMAN__ #include "stdafx.h"
class Human
{
public:
Human();
virtual ~Human(); public:
virtual void eat();
virtual void eat2() = ;
}; #endif // Human.cpp
#include "stdafx.h"
#include "Human.h"
#include <iostream> Human::Human()
{
std::cout << "调用了Human::Human()" << std::endl;
} void Human::eat()
{
std::cout << "人类喜欢吃各种美食" << std::endl;
} Human::~Human()
{
std::cout << "调用了Human::~Human()" << std::endl;
} // Men.h
#ifndef __MEN__
#define __MEN__ #include "stdafx.h"
#include "Human.h" class Men : public Human
{
public:
Men();
~Men();
public:
virtual void eat() override;
virtual void eat2();
}; #endif // Men.cpp
#include "stdafx.h"
#include "Men.h"
#include <iostream> void Men::eat()
{
std::cout << "男人喜欢吃米饭" << std::endl;
} void Men::eat2()
{
std::cout << "男人喜欢吃米饭2" << std::endl;
} Men::Men()
{
std::cout << "调用了Men::Men()" << std::endl;
} Men::~Men()
{
std::cout << "调用了Men::~Men()" << std::endl;
} // Women.h
#ifndef __WOMEN__
#define __WOMEN__
#include "stdafx.h"
#include "Human.h"
class Women : public Human
{
public:
Women();
~Women(); public:
virtual void eat() override;
virtual void eat2() override;
}; #endif // Women.cpp
#include "stdafx.h"
#include "Women.h"
#include <iostream> Women::Women()
{
std::cout << "调用了Women::Women()" << std::endl;
} Women::~Women()
{
std::cout << "调用了Women::~Women()" << std::endl;
} void Women::eat()
{
std::cout << "女人喜欢吃面食" << std::endl;
} void Women::eat2()
{
std::cout << "女人喜欢吃面食2" << std::endl;
} // main.cpp
// Project3.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <iostream>
#include "Human.h"
#include "Men.h"
#include "Women.h" using namespace std; int main()
{
Human *phuman = new Men;
phuman->eat(); // 男人喜欢吃米饭
delete phuman; phuman = new Women;
phuman->eat(); // 女人喜欢吃面食
delete phuman; //phuman = new Human;
//phuman->eat(); // 人类喜欢吃各种美食
//delete phuman;
phuman = new Men;
phuman->eat2(); // 男人喜欢吃米饭
delete phuman; phuman = new Women;
phuman->eat2(); // 女人喜欢吃面食
delete phuman; //Men men;
Men *pmen = new Men;
delete pmen; Human *phuman1 = new Men;
delete phuman1; // 没有执行子类的析构函数 return ;
}

C++基础知识 基类指针、虚函数、多态性、纯虚函数、虚析构的更多相关文章

  1. 虚析构函数? vptr? 指针偏移?多态数组? delete 基类指针 内存泄漏?崩溃?

    五条基本规则: 1.如果基类已经插入了vptr, 则派生类将继承和重用该vptr.vptr(一般在对象内存模型的顶部)必须随着对象类型的变化而不断地改变它的指向,以保证其值和当前对象的实际类型是一致的 ...

  2. 派生类地址比基类地址少4(子类与基类指针强行转换的时候,值居然会发生变化,不知道Delphi BCB是不是也这样) good

    大家对虚表并不陌生,都知道每个含有虚函数的类对象都有1个虚指针,但是在现实使用中,却总是因为这而调试半天,才发现原来是虚指针惹的祸.我这几天在调试代码时候也中招了,我的问题是这样的,如下图,CTree ...

  3. c++ 动态判断基类指针指向的子类类型(typeid)

    我们在程序中定义了一个基类,该基类有n个子类,为了方便,我们经常定义一个基类的指针数组,数组中的每一项指向都指向一个子类,那么在程序中我们如何判断这些基类指针是指向哪个子类呢? 本文提供了两种方法 ( ...

  4. C++ 基类指针,子类指针,多态

    基类指针和子类指针之间相互赋值(1)将子类指针赋值给基类指针时,不需要进行强制类型转换,C++编译器将自动进行类型转换.因为子类对象也是一个基类对象. (2)将基类指针赋值给子类指针时,需要进行强制类 ...

  5. C++ 基类指针和子类指针相互赋值

    首先,给出基类animal和子类fish [cpp] view plaincopy //======================================================== ...

  6. 当this指针成为指向之类的基类指针时,也能形成多态

    this指针: 1)对象中没有函数,只有成员变量 2)对象调用函数,通过this指针告诉函数是哪个对象自己谁. #include<iostream> using namespace std ...

  7. c++基类指针指向继承类调用继承类函数

      类里面重载运算符>>, 需要使用友元函数,而友元函数,不能作为虚函数. 所以,基类指针无法直接调用继承类里重构的 >>  ; 使用类转换,能解决掉,基类指针 调用 继承类 ...

  8. C++获取基类指针所指子类对象的类名

    我们在程序中定义了一个基类,该基类有n个子类,为了方便,我们经常定义一个基类的指针数组,数组中的每一项指向都指向一个子类,那么在程序中我们如何判断这些基类指针是指向哪个子类呢? 关键字 typeid, ...

  9. C++虚复制构造函数,设置Clone()方法返回基类指针,并设置为虚函数

    构造函数不能是虚函数.但有时候确实需要能传递一个指向基类对象的指针,并且有已创建的派生类对象的拷贝.通常在类内部创建一个Clone()方法,并设置为虚函数. //Listing 12.11 Virtu ...

随机推荐

  1. 利用ajaxSubmit()方法实现Form提交表单后回调

    1.      背景 最近在工作中,需要实现网页端图片上传到FTP服务器的功能.上传文件是用Form表单提交数据的方法向后台传输文件流,在此遇到了一个问题:后台在处理完图片上传功能后,需要向前台回传是 ...

  2. sqlserver中怎么查询字段为空的记录

    sqlserver中怎么查询字段为空的记录的两种方法: 详细介绍请查看全文:https://cnblogs.com/qianzf/ 原文博客的链接地址:https://cnblogs.com/qzf/

  3. 2018.09.06 警卫安排(树形dp)

    描述 太平王世子事件后,陆小凤成了皇上特聘的御前一品侍卫. 皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状:有边直接相连的宫殿可以互相望见.大内保卫森严,三步一岗,五步一哨,每个宫殿都要有人全 ...

  4. 2018.08.02 洛谷P3355 骑士共存问题(最小割)

    传送门 这题让我联想到一道叫做方格取数问题的题,如果想使摆的更多,就要使不能摆的更少,因此根据骑士的限制条件建图,求出至少有多少骑士不能摆,减一减就行了. 代码: #include<bits/s ...

  5. spring boot2.0冷知识

    首先,Spring Boot 2.0.0 要求 Java 8 或更高版本,不再支持 Java 6 和 7. 在 Spring Boot 2.0 中,许多配置属性已被重命名或被删除,相应地,开发者需要升 ...

  6. Navicat for oracle cannot load OCI DLL

    Navicat for oracle 提示 cannot load OCI DLL87,126,193 instant client package is required for basic and ...

  7. 多参数同时运行docker

    docker run --name=newtomcat7 -t -i -p 5000:5000 -v /root/work/docker:/root/hzbtest 93541fa83230 /bin ...

  8. C语言之预处理命令与用typedef命名已有类型

    预处理命令 主要是改进程序设计环境,以提高编程效率,不属于c语言本身的组成部分,不能直接对它们进行编译,必须在对 程序编译之前,先对程序中的这些特殊命令进行“预处理”.比如头文件. 有以下三类:宏定义 ...

  9. sql笔试练习

    转:http://www.360doc.com/content/16/0919/17/14804661_592046675.shtml 本文是在Cat Qi的参考原帖的基础之上经本人一题一题练习后编辑 ...

  10. Python 字典(Dictionary) keys()方法

    Python 字典(Dictionary) keys() 函数以列表返回一个字典所有的键. 语法 keys()方法语法: dict.keys() 参数 NA. 返回值 返回一个字典所有的键. 实例 以 ...