#include <iostream>
using std::cout;
using std::endl;
struct Vehicle {
int maxSpeed, weight;
Vehicle(int m, int w) : maxSpeed(m), weight(w) {}
virtual void show() {
cout << "max speed: " << maxSpeed << endl;
cout << "weight: " << weight << endl;
}
};
struct Bicycle : public Vehicle {
int height;
Bicycle(int m, int w, int h) : Vehicle(m, w), height(h) {}
virtual void show() {
Vehicle::show();
cout << "height: " << height << endl;
}
};
struct MotorCar : public Vehicle {
int seatNum;
MotorCar(int m, int w, int s) : Vehicle(m, w), seatNum(s) {}
virtual void show() {
Vehicle::show();
cout << "seat number: " << seatNum << endl;
}
};
int main() {
Vehicle vehicles[] = {
new Bicycle(1, 2, 3), new Bicycle(4, 5, 6), new MotorCar(7, 8, 9)
};
for (int i = 0; i != 3; ++i) {
vehicles[i]->show();
cout << endl;
}
return 0;
}
你理解的是对的,子类和父类各有一个虚函数表,并且虚函数指针也是指向各自的。
子类先是从父类复制了一个虚函数表,如果子类对父类的虚函数进行了覆盖,则在子类的虚函数表将会用子类的函数地址覆盖父类的,如果没有覆盖,则还是使用父类的函数地址,这样就实现了多态。
为了说明虚函数的作用,我们先看一个程序实例:
#include <iostreamh> class vehicle{ int wheels; float weight;public: void message(void) {cout << "Vehicle message\n";}}; class car : public vehicle{ int passenger_load;public: void message(void) {cout << "Car message\n";}}; class truck : public vehicle{ int passenger_load; float payload;public: int passengers(void) {return passenger_load;}}; class boat : public vehicle{ int passenger_load;public: int passengers(void) {return passenger_load;} void message(void) {cout << "Boat message\n";}}; int main(){ vehicle unicycle; car sedan; truck semi; boat sailboat; unicycle = new vehicle; unicycle-> message(); //输出Vehicle message delete unicycle; unicycle = new car; unicycle -> message(); //输出Vehicle message sedan = (car ) unicycle; sedan -> message(); //输出Car message delete sedan; semimessage(); //输出Vehicle message sailboatmessage(); //输出Boat message}
该程序的运行结果,我们已经标注在程序之中。因为指针的类型决定调用那一个成员函数,所以,一个vehicle调用vehicle成员函数,即使它指向派生类的对象。同样,一个car 也调用car 的成员函数。我们把这称为早期联编或静态联编,因为指针要调用那一个函数是在编译时就确定的。
那么,当vehicle指向派生类对象时,我们能不能通过该指针来调用派生类的成员函数呢?在C++中,我们是可以作到的,这要用到C++的多态特性。 也就是说,基类指针是调用基类的成员函数,还是调用派生类的成员函数,不是由指针的类型决定的,而是由指针指向的对象的类型决定的。
虚函数实现机制:
1、当类中存在虚函数里则编译器会在编译期自动的给该类生成一个函数表,并在所有该类的对像中放入一个隐式变量vptr,该变量是一个指针变量,它的值指向那个类中的由编译器生成的 虚函数表
2、每个类自己的虚函数入口都在这张表中维护,调用方法的时候会隐式的传入一个this指针,然后系统会根据this指针找到对应的vptr,进而找到对应的 虚函数表 ,找到真正方法的地址,然后才去调用这个方法,这可以叫动态绑定。
3、 虚函数表 存放重写的虚函数,当基类的指针指向派生类的对象时,调用虚函数时都会根据vptr来选择虚函数,而基类的虚函数在派生类里已经被改写或者说已经不存在了,所以也就只能调用派生类的虚函数版本了
当调用pBase->show();时,执行的步骤:
1, 判断Base类中show是否为虚函数。
2, 若不是虚函数则找到pBase所指向的对象所属类Base。执行Base::show()。若是虚函数则执行步骤3
3, 访问pBase所指对象的虚函数表指针得到pBase所指对象所在类的虚函数表。
4, 查找Base中show()在声明时的位序为x,到步骤3得到的虚函数表中找到位序x,从而得到要执行的show的函数地址。
5, 根据函数地址和Base中声明的show的函数类型(形参和返回值)访问地址所指向的函数。
从虚函数的实现机制可以看到要想在子类中实现多态需要满足三个重要的条件。
(1)在基类中函数声明为虚函数。
(2)在子类中,对基类的虚函数进行了重写。
(3)基类的指针指向了子类的对象。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)