c++是面向对象语言,面向对象有个重要特点,就是继承和多态。继承之前学过了,就是一种重用类的设计方式。原有的类叫父类,或者基类,继承父类的类叫子类。在设计模式中,我们总是要避免继承,推荐用组合。因为继承会导致类爆炸。类太多了,就太累了。。。哈哈。。。

说说多态,多态,从我们语言的语法上说,就是通过父类的指针能直接调用子类的方法,在父类的层面,无需了解子类的实现。在我理解来看,其实多态,也是解耦的一种实现方式,因为子类的实现和父类没有关系了,父类总是可以调用到相关的函数。

但是如果我们父类有完整的一个实现,子类也有完整的实现,肿么办?父类肯定会调用自己的实现方法呀,一会我会讲解这个例子的。为了实现多态,c++语言引用了虚函数的概念。就是说,如果父类的某个函数是虚函数,那么好办,尽管你父类实现了这个虚函数也没关系,我通过指针调用的时候,我也会直接去找子类的相关实现,从而达到多态的效果。这个虚函数就有点像java里面的抽象方法了。但是留意细节哦....c++的虚函数,在父类也是可以实现的。我们来看一个完整的例子。

1 创建一个BaseClass.h的头文件,对父类BaseClass进行声明。

class BaseClass
{
protected:
int x;
int y;
public:
BaseClass();
BaseClass(int a,int b);
void area();
};

2 创建一个BaseClazz.cpp源文件,对父类BaseClass进行实现。

#include <iostream>
#include <string>
#include "BaseClass.h"
using namespace std; BaseClass::BaseClass()
{
x = 1;
y = 2;
}
BaseClass::BaseClass(int a,int b)
{
x = a;
y = b;
}
void BaseClass::area()
{
cout << "baseclass.area() call...." << endl;
cout << x*y <<endl;
}

3 创建一个DeriveClass1.h的头文件,对子类DeriveClass1进行声明。

#include "BaseClass.h"
class DeriveClass1:public BaseClass
{
private:
int z;
public:
void area();
void setValue(int a);
DeriveClass1();
};

4 创建一个DeriveClass1.cpp源文件,对子类进行实现。

#include <iostream>
#include "DeriveClass1.h" using namespace std; void DeriveClass1::area()
{
cout << "DeriveClass1.area() call...." << endl;
cout << x*y*z << endl;
} void DeriveClass1::setValue(int a)
{
z = a;
} DeriveClass1::DeriveClass1()
{
z = 3;
}

看到没有,父类子类都有一个area()函数,父类有两个成员变量x,y,子类有三个x,y,z。

5 创建一个Main.cpp源文件,对以上的代码进行测试。

#include <iostream>
#include "DeriveClass1.h"
using namespace std; int main()
{ BaseClass *dc = new DeriveClass1();
dc->area();
return 1;
}

6 好了,这个时候,由于父类和子类都对area函数进行了实现,通过父类的指针来调用area函数,想都不用想,调用的是父类的area函数,尽管将子类的地址赋值给了父类的指针。看结果。

7 这样一来,多态的效果达不到了么,为了达到多态,肿么办?我们将BaseClass.h头文件中的area函数声明为virtual即可,其他地方均不变。看代码,

class BaseClass
{
protected:
int x;
int y;
public:
BaseClass();
BaseClass(int a,int b);
virtual void area();
};

8 这样一来,我们再次运行第六步的测试代码,截图如下:

这就是父类定义了虚函数的结果,尽管父类实现了该虚函数,但是父类的指针在指向子类的情况下,还是会调用子类对应的函数。

9 这个时候又出现一种情况,如果父类真的是没必要实现这个area函数肿么办??如果你就这样直接不实现,在连接的时候会报错,哈哈。BaseClass.cpp代码如下:

#include <iostream>
#include <string>
#include "BaseClass.h"
using namespace std; BaseClass::BaseClass()
{
x = 1;
y = 2;
}
BaseClass::BaseClass(int a,int b)
{
x = a;
y = b;
}
void BaseClass::area();

连接时报错如下:

--------------------Configuration: DeriveDemo - Win32 Debug--------------------
Compiling...
BaseClazz.cpp
Skipping... (no relevant changes detected)
DeriveClass1.cpp
Linking...
BaseClazz.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall BaseClass::area(void)" (?area@BaseClass@@UAEXXZ)
Debug/DeriveDemo.exe : fatal error LNK1120: 1 unresolved externals
执行 link.exe 时出错. DeriveDemo.exe - 1 error(s), 0 warning(s)

10 这个时候,纯虚函数就派上用场了,我们只需要将虚函数的定义后面赋值为0,即可。看看BaseClass.h头文件的定义。

class BaseClass
{
protected:
int x;
int y;
public:
BaseClass();
BaseClass(int a,int b);
virtual void area()=0;
};

11 然后编译链接执行。。执行结果如下:

12 纯虚函数和虚函数有什么区别,我们通过上面的定义可以看出:

虚函数定义:virtvual void area();

纯虚函数的定义:virtual void area()=0;

虚函数,在父类中是必须实现的。

纯虚函数,在父类中是可以不用实现的。

熟悉java的同学发现这个有没有一点想抽象类和接口呀。哈哈。。

c++学习之多态(虚函数和纯虚函数)的更多相关文章

  1. C++(四十一) — 多态、虚函数、虚析构函数、纯虚函数

     1.多态 面向对象程序设计中,多态性表现为: (1)重载多态:函数重载.运算符重载: (2)运行多态:通过基类的指针(或引用)调用不同派生类的同名函数,表现出不同的行为: (3)模板多态:参数多态, ...

  2. C++ 虚函数 、纯虚函数、接口的实用方法和意义

    也许之前我很少写代码,更很少写面向对象的代码,即使有写多半也很容易写回到面向过程的老路上去.在写面向过程的代码的时候,根本不管什么函数重载和覆盖,想到要什么功能就变得法子的换个函数名字,心里想想:反正 ...

  3. C++ 虚函数与纯虚函数 浅析

    [摘要] 在虚函数与纯虚函数的学习中.要求理解虚函数与纯虚函数的定义,了解虚函数与纯虚函数在实例化上的差异.掌握两者在实现上的必要性.熟悉纯虚函数在子类与孙类的函数类型.本文即针对上述问题展开阐述. ...

  4. c++ 虚函数,纯虚函数的本质区别

    转载博客:https://mp.weixin.qq.com/s?__biz=MzAxNzYzMTU0Ng==&mid=2651289202&idx=1&sn=431ffd1fa ...

  5. c++ 虚函数和纯虚函数

    在你设计一个基类的时候,如果发现一个函数需要在派生类里有不同的表现,那么它就应该是虚的.从设计的角度讲,出现在基类中的虚函数是接口,出现在派生类中的虚函数是接口的具体实现.通过这样的方法,就可以将对象 ...

  6. C++ - 虚基类、虚函数与纯虚函数

    虚基类       在说明其作用前先看一段代码 class A{public:    int iValue;}; class B:public A{public:    void bPrintf(){ ...

  7. C++ Primer--虚函数与纯虚函数的区别

    首先:强调一个概念 定义一个函数为虚函数,不代表函数为不被实现的函数. 定义他为虚函数是为了允许用基类的指针来调用子类的这个函数. 定义一个函数为纯虚函数,才代表函数没有被实现. 定义纯虚函数是为了实 ...

  8. C++ 虚函数与纯虚函数

    #include<iostream> #include<string> using namespace std; class A{ public: virtual void f ...

  9. c/c++ 基金会(七) 功能覆盖,虚函数,纯虚函数控制

    1.功能覆盖 ClassA , ClassB ,其中ClassB继承ClassA 类的定义如下面的: #ifndef _CLASSA_H #define _CLASSA_H #include < ...

  10. 【C++】C++中的虚函数与纯虚函数

    C++中的虚函数 先来看一下实际的场景,就很容易明白为什么要引入虚函数的概念.假设我们有一个基类Base,Base中有一个方法eat:有一个派生类Derived从基类继承来,并且覆盖(Override ...

随机推荐

  1. 【转】Vue v-bind与v-model的区别

    v-model 指令在表单控件元素上创建双向数据绑定,所谓双向绑定,指的就是我们在js中的vue实例中 的data与其渲染的dom元素上的内容保持一致,两者无论谁被改变,另一方也会相应的更新为相同的数 ...

  2. JAVA编程思想读书笔记(四)--对象的克隆

    接上篇JAVA编程思想读书笔记(三)--RTTI No1: 类的克隆 public class MyObject implements Cloneable { int i; public MyObje ...

  3. POJ 2019 Cornfields [二维RMQ]

    题目传送门 Cornfields Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 7963   Accepted: 3822 ...

  4. 首次使用ideal构建maven项目web

    如附件 链接:https://pan.baidu.com/s/1oH-9VfIKnLPjVt-tOH7fZw 提取码:7s5t

  5. 关于 Unity 的一些小细节,不注意可能会被“坑”一些时间。

    关于 Unity 的一些小细节,不注意可能会被"坑"一些时间. 最近因为一些"小"问题,总是需要找很久的原因,总结一下 UnityEngine.Input 在使 ...

  6. Docker应用系列(五)| 构建Mongodb服务器

    本示例基于Centos 7,假设目前使用的账号为release,拥有sudo权限. 由于Docker官方镜像下载较慢,可以开启阿里云的Docker镜像下载加速器,可参考此文进行配置. 主机上服务安装步 ...

  7. 2017 ACM-ICPC 亚洲区(西安赛区)网络赛 xor (根号分治)

    xor There is a tree with nn nodes. For each node, there is an integer value a_ia​i​​, (1 \le a_i \le ...

  8. 图形管线之旅 Part3

    原文:<A trip through the Graphics Pipeline 2011> 翻译:往昔之剑   转载请注明出处   此时,我们一路上通过多个驱动层和命令处理器将draw ...

  9. java 抽象类 接口 区别

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha 接口 里面 都是抽象方法. 接口里面的 字段 都是 public static fina ...

  10. [BZOJ4423][AMPPZ2013]Bytehattan(对偶图+并查集)

    建出对偶图,删除一条边时将两边的格子连边.一条边两端连通当且仅当两边的格子不连通,直接并查集处理即可. #include<cstdio> #include<algorithm> ...