c++学习之多态(虚函数和纯虚函数)
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++学习之多态(虚函数和纯虚函数)的更多相关文章
- C++(四十一) — 多态、虚函数、虚析构函数、纯虚函数
1.多态 面向对象程序设计中,多态性表现为: (1)重载多态:函数重载.运算符重载: (2)运行多态:通过基类的指针(或引用)调用不同派生类的同名函数,表现出不同的行为: (3)模板多态:参数多态, ...
- C++ 虚函数 、纯虚函数、接口的实用方法和意义
也许之前我很少写代码,更很少写面向对象的代码,即使有写多半也很容易写回到面向过程的老路上去.在写面向过程的代码的时候,根本不管什么函数重载和覆盖,想到要什么功能就变得法子的换个函数名字,心里想想:反正 ...
- C++ 虚函数与纯虚函数 浅析
[摘要] 在虚函数与纯虚函数的学习中.要求理解虚函数与纯虚函数的定义,了解虚函数与纯虚函数在实例化上的差异.掌握两者在实现上的必要性.熟悉纯虚函数在子类与孙类的函数类型.本文即针对上述问题展开阐述. ...
- c++ 虚函数,纯虚函数的本质区别
转载博客:https://mp.weixin.qq.com/s?__biz=MzAxNzYzMTU0Ng==&mid=2651289202&idx=1&sn=431ffd1fa ...
- c++ 虚函数和纯虚函数
在你设计一个基类的时候,如果发现一个函数需要在派生类里有不同的表现,那么它就应该是虚的.从设计的角度讲,出现在基类中的虚函数是接口,出现在派生类中的虚函数是接口的具体实现.通过这样的方法,就可以将对象 ...
- C++ - 虚基类、虚函数与纯虚函数
虚基类 在说明其作用前先看一段代码 class A{public: int iValue;}; class B:public A{public: void bPrintf(){ ...
- C++ Primer--虚函数与纯虚函数的区别
首先:强调一个概念 定义一个函数为虚函数,不代表函数为不被实现的函数. 定义他为虚函数是为了允许用基类的指针来调用子类的这个函数. 定义一个函数为纯虚函数,才代表函数没有被实现. 定义纯虚函数是为了实 ...
- C++ 虚函数与纯虚函数
#include<iostream> #include<string> using namespace std; class A{ public: virtual void f ...
- c/c++ 基金会(七) 功能覆盖,虚函数,纯虚函数控制
1.功能覆盖 ClassA , ClassB ,其中ClassB继承ClassA 类的定义如下面的: #ifndef _CLASSA_H #define _CLASSA_H #include < ...
- 【C++】C++中的虚函数与纯虚函数
C++中的虚函数 先来看一下实际的场景,就很容易明白为什么要引入虚函数的概念.假设我们有一个基类Base,Base中有一个方法eat:有一个派生类Derived从基类继承来,并且覆盖(Override ...
随机推荐
- HTML canvas fillText()与measureText()方法
HTML5 canvas fillText() 方法 实例 使用 fillText(),在画布上写文本 "你好!word!" 和 "我是w3c": JavaSc ...
- spring_150907_sqlmapclientdaosupport_getSqlMapClient
1.新建java工程:spring_150907_sqlmapclientdaosupport_getSqlMapClient,如下图所示: 2.工程里添加spring.hibernate.ibati ...
- php将长字符串拆分为指定最大宽度的字符串数组
/** * 将字符串拆分为指定最大宽度的字符串数组.单字节字符宽度为1,多字节字符通常宽度为2 * @param string $msg 要拆分的字符串 * @param int $width 结果数 ...
- 使用 Java 查找字符串中出现次数最多的字符以及出现的次数?
使用 Java 查找字符串中出现次数最多的字符以及出现的次数? import java.util.HashMap; import java.util.Map; public class TestStr ...
- 【U3D】播放器设置(PlayerSettings)
播放器设置 (Player Settings) 播放器设置 (Player Settings) 用于为您要在 Unity 中编译的最终游戏定义各项(特定于平台的)参数.例如,参数中的一些值用于您打开单 ...
- windows下怎样使用md命令一次建立多级子目录
在Windows系统中一次只能够创建一个子目录,在命令提示符窗口则可以一次性创建多个子目录,例如如果想在f盘创建多级子目录,则md 23\13\65\45,后面的数字随便都可以.如果想一次性删除多级目 ...
- 转:win32下的堆管理系统
转:https://bbs.pediy.com/thread-224136.htm 准备刷漏洞战争中的堆溢出部分,但是对于堆的了解较少,在这里记录一下关于堆的学习记录,有错误请各位大大拍砖 参考: & ...
- 《java虚拟机》----虚拟机字节码执行引擎
No1: 物理机的执行引擎是直接建立在处理器.硬件.指令集合操作系统层面上的,而虚拟机的执行引擎则是由自己实现的,因此可以自行制定指令集与执行引擎的结构体系,并且能够执行那些不被硬件直接支持的指令集格 ...
- Java常用工具类之IO流工具类
package com.wazn.learn.util; import java.io.Closeable; import java.io.IOException; /** * IO流工具类 * * ...
- BZOJ1002輪狀病毒 暴搜 + 找規律 + 高精度
@[暴搜, 找規律, 高精度] Description 轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的.一个\(n\)轮状基由圆环上\(n\)个不同的基原子和圆心处一个核原子构成的,2个 ...