代码如下:
class base
{
public:
base()
{
cout << "base()" << endl;
}
virtual void func()
{
cout << "base::func()" << endl;
}
};
class sub:public base
{
public:
sub() :base()
{
cout << "sub()" << endl;
}
void func()
{
cout << "sub::func()" << endl;
}
};
int main() {
sub s;
base& b = s;
b.func();
s.base::func();
}
运行
派生类重写基类的虚函数时,虽然会覆盖虚函数表中基类虚函数的地址,但是基类的虚函数仍然存在于派生类的对象中,可以通过作用域运算符来访问它。因此,当派生类对象通过作用域运算符来调用基类的虚函数时,实际上是直接访问了派生类对象中的基类虚函数地址,而不是通过虚函数表来调用。
具体来说,派生类对象在创建时会包含基类对象的所有成员,包括基类的虚函数表。当派生类重写基类的虚函数时,它会在自己的虚函数表中填入新的函数地址,覆盖基类虚函数表中相应的函数地址。但是,派生类对象中仍然包含了基类的虚函数表,其中仍然保存着基类的虚函数地址。因此,当派生类对象通过作用域运算符来访问基类的虚函数时,它实际上是直接访问派生类对象中的基类虚函数地址,而不是通过虚函数表来调用。
需要注意的是,当基类的虚函数被重写时,为了避免出现未定义的行为,应当将基类的虚函数声明为虚函数,并在派生类中使用override关键字来覆盖它。这样可以确保在派生类对象上调用基类虚函数时,可以正确地访问到派生类对象中的基类虚函数地址。
基类的虚方法也是有方法体的(实现),所以你用s.base::func();是引用基类对象的方法呀。至于为什么这么写,就是语法了。
一个类,它的函数只有一份,不存在一个对象有一份函数的说法,你的例子,基类有一个虚函数表,子类也有一个,作为对象(注意对象和类的区别,就好比人和你的区别是一样的),有个虚表指针(注意是虚表指针,而不是虚表),它指向了子类的虚表,你通过父类引用或指针指向一个子类 ,调用虚函数,他就通过这个虚表指针找到虚函数,再调用达到多态的目的,而你用
s.base::func 则编译器直接就把父类虚表中的函数地址编排到程序里。