背景
- C++虚函数原理和用法及示例:一文带你完全掌握
虚函数原理
- 参考下文:C++虚函数原理
虚函数问题思考
-
1、什么是纯虚函数?(进一步引申出抽象类)
答:纯虚函数是指在基类中声明了虚函数,但是基类没给出实现,子类必须重写该虚函数。并且由于基类虚函数没实现,因此基类是抽象类无法实例出对象。 -
2、虚函数语法?
class Base { public: virtual void show() { std::cout << "Base show()" << std::endl; } virtual void draw() = 0; }; class Derived : public Base { public: void show() override { std::cout << "Derived show()" << std::endl; } void draw() override { std::cout << "Derived draw()" << std::endl; } };
如上,1、基类中通过
virtual
说明是个虚函数,子类在实现时不需要带virtual
,子类通过override
说明该函数是覆盖基类的虚函数的。2、基类中未实现的函数可以通过= 0
来说明是纯虚函数,子类必须实现。3、继承时需要指定继承方式public
或者protected、private
。 -
3、如果基类中不用
virtual
修饰,子类重写了该函数,会怎么样?
答:此时发生了普通函数的覆盖(override),基类函数被隐藏。但由于不是虚函数覆盖,不存在动态绑定,因此此时的覆盖无法实现多态性。例子如下:class Base { public: virtual void show() { std::cout << "Base show()" << std::endl; } void NotVir(void) { cout << "Base not virtual\n"; } }; class Derived : public Base { public: void show() override { std::cout << "Derived show()" << std::endl; } void callBaseShow() { Base::show(); // 显式调用基类的 show(),即使它是虚函数 } void NotVir(void) { cout << "Derived not virtual\n"; } }; int main() { Base b; Derived d; Base *p = &d; p->NotVir();//输出:Base not virtual p->show();//输出:Derived show p = &b; p->NotVir();//输出:Base not virtual p->show();//输出:Base show return 0; }
可以看出,普通函数的覆盖不能实现多态,而虚函数的覆盖可以实现多态。
-
4、发生函数覆盖
override
时,通过子类域说明符调用基类函数的语法合法吗?
答:合法。以上述 例子3 中的代码,改main函数如下:int main() { Base b; Derived d; Base *p = &d; d.show(); // 输出: Derived show() d.callBaseShow(); // 输出: Base show() d.Base::show(); // 输出: Base show() d.NotVir(); // 输出: Derived not virtual d.Base::NotVir(); //输出:Base not virtual p->show(); // 输出: Derived show() //p->callBaseShow(); // 语法错误,因为p是Base类型,不知道callBaseShow存在 p->Base::show(); // 输出: Base show() p->NotVir(); // 输出: Base not virtual p->Base::NotVir(); //输出:Base not virtual return 0; }
从上述例子可以看出:1、对于子类中的新函数,基类指针无法得知更无法访问。2、对于非虚函数的覆盖,基类指针只能执行基类中的函数,无法实现动态绑定,哪怕通过域说明符也是只执行基类中的函数。
-
5、继承方式
答:区别如下:
并且private继承时,基类的指针不能指向子类成员。并且对象也不能访问private成员,只能类内部的代码访问。