C++中虚函数是通过一张虚函数表来实现的,简称V-Table,在C++的标准规格说明书中说到,编译器必须要保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证正确取到虚函数的偏移量)。
一般继承且无虚函数覆盖
上面图中的这个点是虚函数的结束标志,就像字符串中的‘\0’ 一样。不同的编译器结束标志可能会不一样。
如果是多重继承并且无虚函数覆盖
1.每一个父类都有自己的虚表
2.子类 的虚成员函数被放到了第一个父类 的表中(按照声明的顺序的第一个)。
如果有虚函数覆盖,则覆盖的函数被放在虚表中原来父类虚函数的位置。没有被覆盖 的函数依旧。
基类的指针指向子类的对象,这个指针只能调用基类的成员函数,
pt->run(); //‘class Animal’ has no member named ‘run’ pt->run();
//会报错,任何妄图使用父类指针想调用子类中的未覆盖父类的成员函数的行为都会被编译器视为非法。所以根本无法编译通过,并且这个指针只能调用基类的成员函数,如果想在子类中重写这个函数,必须在基类中这个函数前加上一个virtual,否则如果子类和基类 中都有这个函数,则会调用基类中的这个函数,因为是基类类型的指针。如果还想调用这个函数可以在子类的这个函数里加上Animal::eat(),比如:
void Fish::eat()
{
Animal::eat();
cout<<“fish eat”<<endl;
}
这样既调用了基类中的这个函数又调用了子类中的这个函数(既做花轿又做汽车)。
如果定义了一个子类的指针,用这个指针调用子类和基类都有的函数,则这个指针会调用子类的函数,虽然也继承了基类中的这个函数,但是子类中的这个函数会覆盖掉基类中的这个函数,这就是函数的覆盖。
函数的覆盖
函数的覆盖是发生在子类与基类当中的,而函数的重载 是发生在同一个类当中的。
当子类和父类void breath()这个函数,子类的对象会调用子类的breath函数,会覆盖掉基类的breath函数,如果想调用基类的breath函数则可以按照上述的方法。
void Fish::eat()
{
Animal::eat();
cout<<“fish eat”<<endl;
}