一、单继承下的虚函数
class Base
{
public:
virtual void f()
{
cout << "Base:f()" << endl;
}
virtual void g()
{
cout << "Base:g()" << endl;
}
virtual void h()
{
cout << "Base:h()" << endl;
}
};
class Derive :public Base
{
public:
virtual void g()
{
cout << "Derive:g()" << endl;
}
void myselffunc()
{
}
};
下面是这个类的图 如果在子类中增加一个虚函数i,如下:
virutal void i()
{
}
那布局图有所改变,如下: 看如下代码:
void main()
{
Base *pbase = new Derive();
pbase->g();
Derive d;
Base &base = d;
base.g();
system("pause");
}
结果: 其实我们唯一需要在执行期间知道的东西就是通过哪个虚函数表来调用虚函数(父类的还是子类的)。
二、回顾和一些小实验
虚函数地址:编译期间知道,写在可执行文件中,编译期间已经构建出来了。 vptr编译期间产生,编译器在构造函数中插入给vptr赋值的代码,当创建对象时,因为要执行构造函数,此时vptr被赋值。
看如下代码:
class Base
{
public:
Base()
{
printf("%p\n",this);
}
virtual void f()
{
cout << "Base:f()" << endl;
}
virtual void g()
{
cout << "Base:g()" << endl;
}
virtual void h()
{
cout << "Base:h()" << endl;
}
};
class Derive :public Base
{
public:
Derive()
{
printf("%p\n", this);
}
virtual void g()
{
cout << "Derive:g()" << endl;
}
};
void main()
{
Derive d1;
Derive d2;
printf("d1的虚函数表地址:%p\n",*(&d1));
printf("d2的虚函数表地址:%p\n", *(&d2));
system("pause");
}
结果: 从结果可以看出,同一类的不同对象的虚函数表的地址相同,也就是说所有的对象共用一个虚函数表。 接下来看看,如果子类不重写父类的任何虚函数,那会不会子类和父类共用一个虚函数表呢? 看代码:
class Base
{
public:
Base()
{
printf("%p\n",this);
}
virtual void f()
{
cout << "Base:f()" << endl;
}
virtual void g()
{
cout << "Base:g()" << endl;
}
virtual void h()
{
cout << "Base:h()" << endl;
}
};
class Derive :public Base
{
public:
Derive()
{
printf("%p\n", this);
}
};
void main()
{
Derive d1;
Derive d2;
printf("d1的虚函数表地址:%p\n",*(&d1));
printf("d2的虚函数表地址:%p\n", *(&d2));
Base base;
printf("base的虚函数表地址:%p\n", *(&base));
system("pause");
}
结果: 从结果可以看出,尽管子类没有重写父类的任何虚函数,但是他们的虚函数表的地址还是不同。
所以每一个类都对应一个独立的虚函数表,不管有没有重写父类的虚函数。
|