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

父类指针可以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. ApplicationContextAware学习--存疑问题

    先看下ApplicationContextAware的源码:     package org.springframework.context; import org.springframework.b ...

  2. WPF 嵌入字体文件

    官方说明文档:将字体与应用程序一起打包 https://docs.microsoft.com/zh-cn/dotnet/framework/wpf/advanced/packaging-fonts-w ...

  3. sqlite3数据库,增删改查

    搜索libsql //由于文件读写,归档,NSUserDefault,做持久存储的时候,是一个覆盖的过程,效率太低,更多的时候使用数据库来做持久化存储         //鉴于手机的硬件配置,使用轻量 ...

  4. pytest 入门及运行

    关于pytest的入门教程,官网及网上已经很多了,那再多一点也无所谓吧!OK,进入正题~ 下面是一个测试用例,test_one.py def test_passing():    assert (1, ...

  5. C++主流编译器整理(编译器版本--供应商--C++11支持情况)

    C++标准   年份 C++标准                俗称   备注 2011 ISO/IEC 14882:2011     C++11  第三个C++标准 2007 ISO/IEC TR ...

  6. TCP/IP模型的一个简单解释

    TCP/IP模型是互联网的基础. 想要理解互联网,就必须理解这个模型.但是,它不好懂,我就从来没有搞懂过. 前几天,BetterExplained上有一篇文章,很通俗地解释了这个模型.我读后有一种恍然 ...

  7. fully delete project in Eclipse

    选择你的项目(test)右击,选择delete——弹出框中勾选删除全部,如下如所示: 正常情况下,这样就能删除干净了,有时候你项目在运行,这时候你点击删除,那就会报下面的错误提示,虽然不会影响你其它项 ...

  8. [smarty] 在smarty模板中使用smarty变量初始化 javascript 变量的问题

    // 总结:// 1/ 在smarty 模板文件中,使用从php中assign过来的smarty变量,一定需要使用双引号或单引号来括住smarty变量,如:var title="<!- ...

  9. plsql高版本无法设置Fixedsys字体解决办法(win7&winXP适用)

    http://hi.baidu.com/crsky2008/item/c174c9fb52577919e3e3bd6b 设置如下:Tools->Preferences->Oracle-&g ...

  10. Java何时该使用覆盖?

    在Java编程中,什么时候该使用覆盖函数操作呢,很多人都知道有覆盖操作,但是到底什么时候该使用覆盖操作,还是有一些模糊的感觉,以下就举例来用代码分析就明白了, 举例生活中的案例,模拟制造手机的公司: ...