虚函数是 C++语言中的一个相当重要的概念,特别对于 C 程序员来说,本身并没有精力去系统的学习 C++ 中的一些概念,比如虚基类、虚函数等, C++ 语言不似 C 语言这般简洁,纷繁复杂,像是大杂烩,这也是我早期相当讨厌 C++ 语言的原因,但是它也有其独到之处,作为现代的 C 程序员,难免会接触 C++ ,而也是因为 C++ 语言的繁乱,所以我们学习的时候一定要抓住本质,下面的是我针对 C++ 中虚函数的一些总结 , 我们将从虚函数的定义、作用功能、应用举例、实现机制由浅入深的来阐述虚函数,希望在升华自我的同时也能够帮助到读者 .........
一、 虚函数的定义
虚函数必须为基类的非静态函数和非构造函数
其访问权限可以是protected ,当然也可以是 public
在基类中定义虚函数的一般形式: virtual 函数返回值类型 虚函数名(形参表) {函数体 }
特出情况:如果基类中无法实现该函数或者没有必要实现那么可以采用纯虚函数
纯虚函数的形式: virtual 函数返回值类型 虚函数名 = 0 ;
而包含有纯虚函数的类我们成为抽象类。
基类中定义过的虚函数若在派生类中重新定义,那么是否加 virtual 修饰就随你而定
二、 虚函数的作用
实现动态联编(编译时不知道具体行为,当运行时才可确定),
基类中定义了虚函数过后可以在其派生类中重新定义,若没有重新定义那么将继承基类 中的虚函数,但发现函数前 virtual 之后,系统会自动按照动态联编来处理,
虚函数也是C++ 中多态的一种实现,即不同对象传入相同消息后的不同表现
实现动态联编一般需要以下三个条件:
1、 必须把动态联编的行为定义为类的虚函数。
2 、类之间存在子类型关系,一般表现为 一个类从另一个类公有派生而来。
3、必须先使用基类指针指向子类型的对象,然后直接或者间接使用基类指针调用虚函数
三、 应用举例
Animal
Animal();
virtual ~Animal();
virtual void shout();
char *name;
Dog
Dog();
virtual ~Dog();
Cat
Cat();
virtual ~Cat();
animal 派生 dog 和 cat
#include <stdio.h>
#include <string.h>
class Animal
{
public:
char *name;
Animal(char *name);
virtual ~Animal();
virtual void shout() = 0;
};
Animal::Animal(char *name)
{
this->name = new char[strlen(name)];
strcpy(this->name,name);
}
Animal::~Animal()
{
delete []name;
}
class Dog : public Animal
{
public:
Dog(char *name);
virtual ~Dog();
virtual void shout();
};
Dog::Dog(char *name):Animal(name)
{
this->name = new char[strlen(name)];
strcpy(this->name,name);
}
Dog::~Dog()
{
delete []name;
}
void Dog::shout()
{
printf("Dog shout!!!!/n");
}
class Cat : public Animal
{
public:
Cat(char *name);
virtual ~Cat();
virtual void shout();
};
Cat::Cat(char *name):Animal(name)
{
this->name = new char[strlen(name)];
strcpy(this->name,name);
}
Cat::~Cat()
{
delete []name;
}
void Cat::shout()
{
printf("Cat shout!!!!/n");
}
int main(int argc, char **argv)
{
Animal *dog = new Dog("Dog");
Animal *cat = new Cat("Cat");
dog->shout();
cat->shout();
return 0;
}
一、 实现机制
包含或其父类包含虚函数的类都有一个虚表,其对象都会有一个虚指针,该指针指向虚表的首地址:
A
virtual f(); VTABLE: f() g() e()
virtual g();
virtual e();
B
virtual t(); VTABLE: t() v() y()
virtual v();
virtual y();
C继承A和B
C
virtual t(); VTABLE: f() g() e()
virtual v(); t() v() y()
virtual f();
virtual g();
其中红色的为在子类中覆盖了父类函数,黑色为没有覆盖,注意,C 的实例不可以调用 e() y (),当 C 实例化对象时候,就会给它分配一个 VPTR 指针指向该类的虚表,用父类对象指针指向子类对象,也同样会调用被子类覆盖了的函数。