C++虚函数入门
来源:互联网 发布:知乎日报启动画面 编辑:程序博客网 时间:2024/06/07 01:56
参考博客:
1. 虚函数与纯虚函数
2. 虚函数和纯虚函数的作用与区别
3. C++一些注意点之友元函数、虚函数以及const和volatile对象
case 1 :没有用虚函数的情况:
//virtual.h#include <iostream>#include <string>using namespace std;class Animal{private:string m_name;public:Animal(string n):m_name(n){};~Animal(){cout<<"destructor of Animal::"<<getName()<<endl;}string getName(){return m_name;}void setName(string n){m_name = n;}void bark(){cout<<"Bark~Animal::"<<getName()<<endl;}};class Dog:public Animal{public:Dog(string n):Animal(n){};void bark(){cout<<"Bark~Dog!"<<getName()<<endl;}~Dog(){cout<<"destructor of Dog::"<<getName()<<endl;}};
//virtual.cpp#include "virtualFunc.h"int main(){Animal p("Alex");Dog d("Ben");p.bark();d.bark();Animal* p_a = NULL;p_a = &p;p_a->bark();p_a = &d;p_a->bark();return 0;}
运行结果:
至于最后两个bark都是调用基类Animal::bark(),是因为p_a是定义为Animal的指针,调用bark()时,bark()不是虚函数,所以直接调基类Animal::bark()。
case 2:下面加上虚函数来看看。只要在bark函数前加上virtual即可:
virtual void bark(){cout<<"Bark~Animal::"<<getName()<<endl;}
virtual void bark(){cout<<"Bark~Dog!"<<getName()<<endl;}
再加上一个Cat,没有复写bark():
class Cat:public Animal{public:Cat(string n):Animal(n){};//virtual void bark(){cout<<"Bark~Cat!"<<getName()<<endl;}~Cat(){cout<<"destructor of Cat::"<<getName()<<endl;}};然后main函数里,将p_a指向Cat实例,并调用bark():
#include "virtualFunc.h"int main(){Animal p("Alex");Dog d("Ben");Cat c("Cindy");p.bark();d.bark();Animal* p_a = NULL;p_a = &p;p_a->bark();p_a = &d;p_a->bark();p_a = &c;p_a->bark();return 0;}
运行结果:
可以看到加上virtual的效果了。p_a调用子类Dog::bark()!因为每种动物的bark()都会不同,所以在基类Animal里将bark定义为virtual,子类就可以复写。当子类没有bark()的时候,才去调基类的bark()。
case 3:如果改成纯虚函数
基类Animal里将bark改成如下:
virtual void bark()=0;运行,发现报错!
error C2259:'Animal‘:cannot instanitate abstract class
error C2259:'Cat‘:cannot instanitate abstract class
这就是纯虚函数的一个要注意的地方:有纯虚函数的类,称为虚基类,是不可以实例化!只可以声明指针。
Cat有问题是因为,Cat继承Animal,Animal的bark()是虚基类,在子类里必须要实现,所以在Cat里要将bark()实现,否则Cat也不能实例化,因为它和基类一样,也是抽象类!
那么改成如下:
#include <iostream>#include <string>using namespace std;class Animal{private:string m_name;public:Animal(string n):m_name(n){};~Animal(){cout<<"destructor of Animal::"<<getName()<<endl;}string getName(){return m_name;}void setName(string n){m_name = n;}//virtual void bark(){cout<<"Bark~Animal::"<<getName()<<endl;};virtual void bark()=0;};class Dog:public Animal{public:Dog(string n):Animal(n){};virtual void bark(){cout<<"Bark~Dog!"<<getName()<<endl;}~Dog(){cout<<"destructor of Dog::"<<getName()<<endl;}};class Cat:public Animal{public:Cat(string n):Animal(n){};virtual void bark(){cout<<"Bark~Cat!"<<getName()<<endl;}~Cat(){cout<<"destructor of Cat::"<<getName()<<endl;}};
#include "virtualFunc.h"int main(){Animal* p;Dog d("Ben");Cat c("Cindy");p = &d;p->bark();d.bark();c.bark();p = &c;p->bark();return 0;}
运行结果如下:
至于纯虚函数的总结:
1. 只定义,并不去实现。给出函数的接口,在子类里去实现。
但是通常我们可以看到函数后有加上const=0,下面引出const函数。
还是原先的例子,改成如下:
#include <iostream>#include <string>using namespace std;class Animal{private:string m_name;public:Animal(string n):m_name(n){};~Animal(){cout<<"destructor of Animal::"<<getName()<<endl;}string getName(){return m_name;}void setName(string n){m_name = n;}virtual void bark()const{cout<<"Bark~Animal::"<<getName()<<endl;};//加上const修饰};class Dog:public Animal{public:Dog(string n):Animal(n){};virtual void bark() {cout<<"Bark~Dog!"<<getName()<<endl;}~Dog(){cout<<"destructor of Dog::"<<endl;}};class Cat:public Animal{public:Cat(string n):Animal(n){};virtual void bark() {cout<<"Bark~Cat!"<<getName()<<endl;}~Cat(){cout<<"destructor of Cat::"<<endl;}};
运行报错!
error C2662: 'Animal::getName' : cannot convert 'this' pointer from 'const Animal' to 'Animal &'
解决:是因为const函数bark()里调了getName(),如果把它删了,则正常了。可是如果我们想要调它怎么办呢?把getName()也改成const函数即可!const修饰的对象只能访问const修饰的函数成员,不能访问其他成员函数。getName()之前是非const函数,所以bark()不能访问。
至于为什么要用const修饰?如果我们用const 修饰getName()后,在getName()里去修改m_name,编译器会报错!不用const修饰,修改则没事。所以const用于告诉编译器,这个函数里不允许修改任何类的数据。同理,它只能调其他const函数成员,是因为如果掉非const函数的话,有可能会修改类的数据。
到这里,我们知道在函数后加上const=0是什么意思了。const修饰函数为常函数,=0表明它是纯虚函数(当然要有virtual)。它必须:
1. 基类只声明,不实现。
2. 派生类里的纯虚函数之能调用const函数。
- C 语言相关函数入门
- C入门:C标准时间函数
- 【C/C++语言入门篇】-- 深入函数
- 【C/C++语言入门篇】-- 深入函数
- Unity3D入门:常用方法、函数(C#)
- c语言入门(七)函数
- Objective-C入门05:自定义构造函数
- c语言入门——printf函数
- C语言入门(十五)函数递归
- 用函数求最大值-C入门习题
- C/C++--虚函数
- C++虚函数入门
- C语言入门(十九)指针函数和函数指针
- C语言入门一:C语言的main函数写法
- C/C++ACM入门之输入函数格式控制
- linux下c语言入门02 c语言特性及函数入门
- 【C/C++】纯虚函数
- C/C++, 虚函数表
- 实验常用正交表
- R语言与数据挖掘学习笔记(常用的包)
- 快逸报表中配置DB2数据源
- Java操作XML文件(1)-写入XML文件
- 控件旋转动画效果
- C++虚函数入门
- 建筑物的轮廓问题
- 一个PHP程序员应该掌握的10项技能!
- 易信,不改难成大事
- Java 判断字符串是否为空的三种方法
- cacti 画图 断续问题处理
- ORA-03113 解决办法
- sqlserver2008 安装 出现"服务SQLBrowser启动请求失败”
- ubuntu 配置ganlia监控hadoop 单机配置