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 ...
随机推荐
- Jquery 实现轮播图
jq 轮播图 function banner_show(){ var left_btn = $("#banner_tag_left"); //获取左侧单击按钮 var right_ ...
- 牛客练习赛19 D-托米去购物
最裸的最大流,没啥好说的.. #include<bits/stdc++.h> #define LL long long #define fi first #define se second ...
- AppDomain.CurrentDomain.BaseDirectory是什么
AppDomain.CurrentDomain.BaseDirectory 是获取基目录,它由程序集冲突解决程序用来探测程序集.由显示的路径可以看出,它代表的是程序集所在的目录,它具有读取和写入的属性 ...
- django 编码错误
估计这个问题是2.7的问题3.0好像就统一utf编码了 报错代码: python :ascii codec can't decode byte 0xe8 in posi 当django中报这个错误的时 ...
- python 学习笔记 - Queue & Pipes,进程间通讯
上面写了Python如何创建多个进程,但是前面文章中创建的进程都是哑巴和聋子,自己顾自己执行,不会相互交流.那么如何让进程间相互说说话呢?Python为我们提供了一个函数multiprocessing ...
- 颓废选手在 Ubuntu/Noilinux 下的生存指北
颓废选手在 Ubuntu/Noilinux 下的生存指北 Hint: 这里的 "#" 都是假注释,复制的时候记得删除 一些基本的生存命令 ctrl + alt + t #调出终端 ...
- 「BZOJ 2534」 L - gap字符串
「BZOJ 2534」 L - gap字符串 题目描述 有一种形如 \(uv u\) 形式的字符串,其中 \(u\) 是非空字符串,且 \(v\) 的长度正好为 \(L\), 那么称这个字符串为 \( ...
- Java并发(十四):并发工具类——CountDownLatch
先做总结: 1.CountDownLatch 是什么? CountDownLatch 允许一个或多个线程等待其他线程(不一定是线程,某个操作)完成之后再执行. CountDownLatch的构造函数接 ...
- bzoj 4769: 超级贞鱼 -- 归并排序
4769: 超级贞鱼 Time Limit: 1 Sec Memory Limit: 128 MB Description 马达加斯加贞鱼是一种神奇的双脚贞鱼,它们把自己的智慧写在脚上——每只贞鱼的 ...
- HDU 5652 India and China Origins 二分+并查集
India and China Origins 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5652 Description A long time ...