虚函数
概念:在类成员函数声明前加上virtual关键字的函数。
当基类的成员函数无法满足子类要求的时候,我们可以将改成员函数声明为虚函数,以供子类改写,虚函数的声明方式如下:
class 基类名
{
virtual 返回类型斜体样式 函数名(参数列表)
};
虚函数列表
当一个类中出现了虚函数时,编译器会为这个类的对象多分配4个字节的空间用于存放虚函数列表。
在虚拟列表中存放了所有虚函数的函数指针。
当对象调用虚函数时,会优先从虚函数列表中寻找匹配的函数指针进行调用。
- vi Animal.h
#ifndef _ANIMAL_H
#define _ANIMAL_H
class Animal
{
public:
int weight;
int age;
Animal(int weight,int age);
void eat();
};
#endif
Animal .cpp
#include"Animal.h"
#include <iostream>
using namespace std;
Animal::Animal(int weight,int age)
:weight(weight),age(age)
{
}
void Animal::eat()
{
cout<<"Animal eat"<<endl;
}
main.cpp
#include"Animal.h"
#include <iostream>
using namespace std
int main(int arg,char **argv)
{
cout<<"Animal: "<<sizeof(Animal)<<endl;
return 0;
}
运行结果
虚函数代码
#ifndef _ANIMAL_H
#define _ANIMAL_H
class Animal
{
public:
int weight;
int age;
Animal(int weight,int age);
virtual void eat();
};
#endif
运行结果
大小有8变成12,多出来的4字节就是虚函数字节。
指针偏移
#include"Animal.h"
#include <iostream>
using namespace std;
int main(int arg,char **argv)
{
//cout<<"Animal: "<<sizeof(Animal)<<endl;
Animal animal(100,5);
int *p = (int*)&animal
cout<<*p<<endl;
p++;
cout<<*p<<endl;
p++;
cout<<*p<<endl;
return 0;
}
运行结果
通过函数指针去打印出存放在对象里的虚函数,通过指针函数打印出对象里的成员
#include"Animal.h"
#include <iostream>
using namespace std
typedef void (*fun_t)(void);//
int main(int arg,char **argv)
{
//cout<<"Animal: "<<sizeof(Animal)<<endl;
Animal animal(100,5);
int *p = (int*)&animal
fun_t** pFuns = (fun_t**)p;//指向函数指针的二级指针
(*pFuns)[0]();//
p++;
cout<<*p<<endl;
p++;
cout<<*p<<endl
return 0;
}
运行结果
分析图
函数重写
概念:派生类对基类的虚函数进行重新定义的行为。函数重写会将派生类对象继承自基类的虚函数列表部分进行重写。
- vi Animal.h Animal.cpp main.cpp
#ifndef _ANIMAL_H
#define _ANIMAL_H
class Animal
{
public:
int weight;
int age;
Animal(int weight,int age);
virtual void eat();
};
class Cat:public Animal
{
private:
int color;
public:
Cat(int color,int weight,int age);
virtual void eat();
};
#endif
Animal.cpp
#include"Animal.h"
#include <iostream>
using namespace std;
Animal::Animal(int weight,int age)
:weight(weight),age(age)
{
}
void Animal::eat()
{
cout<<"Animal eat"<<endl;
}
Cat::Cat(int color,int weight,int age)
:Animal(weight,age),color(color)
{
}
void Cat::eat()
{
cout<<"eat fish"<<endl;
}
main.cpp
#include"Animal.h"
#include <iostream>
using namespace std
int main(int arg,char **argv)
{
Animal animal(100,5);
animal.eat();
Cat cat(0,100,5);
cat.eat();
return 0;
}
运行结果
函数重写
#include"Animal.h"
#include <iostream>
using namespace std;
Animal::Animal(int weight,int age)
:weight(weight),age(age)
{
}
void Animal::eat()
{
cout<<"Animal eat"<<endl;
}
Cat::Cat(int color,int weight,int age)
:Animal(weight,age),color(color)
{
}
void Cat::eat()
{
Animal::eat();//函数重写
cout<<"eat fish"<<endl;
}
运行结果