C++基础知识 基类指针、虚函数、多态性、纯虚函数、虚析构
一、基类指针、派生类指针
父类指针可以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++基础知识 基类指针、虚函数、多态性、纯虚函数、虚析构的更多相关文章
- 虚析构函数? vptr? 指针偏移?多态数组? delete 基类指针 内存泄漏?崩溃?
五条基本规则: 1.如果基类已经插入了vptr, 则派生类将继承和重用该vptr.vptr(一般在对象内存模型的顶部)必须随着对象类型的变化而不断地改变它的指向,以保证其值和当前对象的实际类型是一致的 ...
- 派生类地址比基类地址少4(子类与基类指针强行转换的时候,值居然会发生变化,不知道Delphi BCB是不是也这样) good
大家对虚表并不陌生,都知道每个含有虚函数的类对象都有1个虚指针,但是在现实使用中,却总是因为这而调试半天,才发现原来是虚指针惹的祸.我这几天在调试代码时候也中招了,我的问题是这样的,如下图,CTree ...
- c++ 动态判断基类指针指向的子类类型(typeid)
我们在程序中定义了一个基类,该基类有n个子类,为了方便,我们经常定义一个基类的指针数组,数组中的每一项指向都指向一个子类,那么在程序中我们如何判断这些基类指针是指向哪个子类呢? 本文提供了两种方法 ( ...
- C++ 基类指针,子类指针,多态
基类指针和子类指针之间相互赋值(1)将子类指针赋值给基类指针时,不需要进行强制类型转换,C++编译器将自动进行类型转换.因为子类对象也是一个基类对象. (2)将基类指针赋值给子类指针时,需要进行强制类 ...
- C++ 基类指针和子类指针相互赋值
首先,给出基类animal和子类fish [cpp] view plaincopy //======================================================== ...
- 当this指针成为指向之类的基类指针时,也能形成多态
this指针: 1)对象中没有函数,只有成员变量 2)对象调用函数,通过this指针告诉函数是哪个对象自己谁. #include<iostream> using namespace std ...
- c++基类指针指向继承类调用继承类函数
类里面重载运算符>>, 需要使用友元函数,而友元函数,不能作为虚函数. 所以,基类指针无法直接调用继承类里重构的 >> ; 使用类转换,能解决掉,基类指针 调用 继承类 ...
- C++获取基类指针所指子类对象的类名
我们在程序中定义了一个基类,该基类有n个子类,为了方便,我们经常定义一个基类的指针数组,数组中的每一项指向都指向一个子类,那么在程序中我们如何判断这些基类指针是指向哪个子类呢? 关键字 typeid, ...
- C++虚复制构造函数,设置Clone()方法返回基类指针,并设置为虚函数
构造函数不能是虚函数.但有时候确实需要能传递一个指向基类对象的指针,并且有已创建的派生类对象的拷贝.通常在类内部创建一个Clone()方法,并设置为虚函数. //Listing 12.11 Virtu ...
随机推荐
- 2018.06.29 洛谷P1505 [国家集训队]旅游(树链剖分)
旅游 题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有 ...
- derective示例
1.指令的定义 .directive('haproxySetting', [ function () { return { restrict: 'AEC', scope: { haproxy: '=' ...
- DataFrame按行读取:DataFrame之values
http://blog.csdn.net/u014607457/article/details/51290582 def fill_core(self): RatingTable=pd.read_cs ...
- 静态代码块和this
/* 静态代码块.随着类的加载而执行.而且只执行一次. 作用: 用于给类进行初始化. */class StaticCode{ static int num ; static { num = 10;// ...
- mybatis操作数据库
导入jar包 共13包 注意:mysql-connction的版本是5.1.7版低版本可能不行 2.编写配置文件 a. 配置连接数据库的文件 a.1创建数据库 user表 a.2配置文件目录 a.2. ...
- 从问题域看hadoop的各种技术
近些年来Hadoop生态系统发展迅猛,它本身包含的软件越来越多,同时带动了周边系统的繁荣发展.尤其是在分布式计算这一领域,系统繁多纷杂,时不时冒出一个系统,号称自己比MapReduce或者Hive高效 ...
- Python学习-3.Python的模块加载
Python中使用import关键字进行模块加载. 先在Visual Studio中建立PythonModuleLoad项目作为演示. 1.同目录加载 建立SameFolder.py文件 写入代码: ...
- 利用Kettle进行SQLServer与Oracle之间的数据迁移实践
Kettle简介 Kettle(网地址为http://kettle.pentaho.org/)是一款国外开源的ETL工具,纯java编写,可以在Windows.Linux.Unix上运行,数据抽取高效 ...
- RESTful Android
RESTful Android API 定义 约定 回复中默认包含标头: Content-Type: application/json;charset=UTF-8 异步操作以(*)号标记 大多数异步操 ...
- MongoDB与SqlSugar与Ado.Net对比
SqlSugar NET 4.+ & .NET CORE 高性能 轻量级 ORM框架,众多.NET框架中最容易使用的数据库访问技术 MongoDB与MySql的安装省略...虽然遇到了一些意外 ...