【复习】C++之虚函数与多态

C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。所谓泛型技术就是试图使用不变的代码来实现可变的算法。比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议。

对C++了解的人都应该知道虚函数是通过一张虚函数表来实现的。在这个表中,主要是一个类的虚函数地址表,虚拟函数表是在编译时期就建立了,各个虚拟函数这时被组织成了一个虚拟函数的入口地址的数组,而对象的隐藏成员,虚拟函数表指针是在运行时期,也就是构造函数被调用时进行初始化的,这时实现多态的关键。

在C++的标准规格说明书中说道,编译器必须要保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证正确取到虚函数的偏移量)。这意味着我们通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。

多态是基于虚函数完成,虚函数基于重写。

Q:虚函数怎么实现多态原理?

通过维护一个虚函数列表v_table,虚函数列表的每个元素是一个函数指针,指向一个虚函数,或者子类重写函数。需要vfptr记录这个类所使用那个虚函数列表,之后 要用父类的指针调用虚函数,通过vfptr找到v_table列表中的函数调用。

v_table虚函数列表在编译期创建,vfptr指向表的指针在创建对象的指针时存在,是父类中的第一个数据成员,并且在构造函数里的初始化指向自己类中。

虚函数实现多态的优点:复用,扩展。

虚函数实现多态的缺点:虚函数列表的空间,效率,安全性。

Q:哪些函数需要使用虚函数,什么时候实现多态?

如果父类的指针指向子类的对象,需要使用子类的东西都要是虚函数的。

Q:什么时候出现父类的指针指向子类的对象?

把不同的类型统一成同一个种类。

关于安全性

通过父类型的指针访问子类自己的虚函数,任何妄图使用父类指针想调用子类中未覆盖父类的成员函数的行为都会被编译器视为非法。但在运行时可以通过指针的方式访问虚函数列表来达到目的。

另外,如果父类的虚函数是private或是protected的,但这些非public的虚函数同样会存在于虚函数列表中,所以我们同样可以使用访问虚函数列表的方式来访问这些non-public的虚函数。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个使用C++虚函数实现多态的代码示例: ```cpp #include <iostream> using namespace std; class A { public: virtual void foo() { cout << "A::foo()" << endl; } virtual ~A() { cout << "~A()" << endl; } }; class B : public A { public: void foo() { cout << "B::foo()" << endl; } ~B() { cout << "~B()" << endl; } }; int main() { A* p = new B(); p->foo(); delete p; return 0; } ``` 在这个示例中,类A和类B都有一个名为foo()的虚函数。当我们通过基类指针p调用foo()函数时,实际上会根据指针所指向的对象的类型来确定调用哪个类的foo()函数。这就是多态的实现原理。 输出结果为: ``` B::foo() ~B() ~A() ``` 可以看到,通过虚函数实现的多态,调用的是派生类B的foo()函数,而不是基类A的foo()函数。同时,析构函数也是虚函数,确保在删除指针p时,会先调用派生类B的析构函数,再调用基类A的析构函数。这是因为在C++中,如果基类的析构函数不是虚函数,那么通过基类指针删除派生类对象时,只会调用基类的析构函数,而不会调用派生类的析构函数。因此,为了确保正确的析构顺序,析构函数应该声明为虚函数。 请注意,虚函数只能在类的成员函数中声明,构造函数不能声明为虚函数。这是因为在创建对象时,需要先调用构造函数来初始化对象,而虚函数的机制是在运行时根据对象的类型来确定调用哪个函数,而构造函数在对象创建时就已经确定了。因此,构造函数不能声明为虚函数。 #### 引用[.reference_title] - *1* [虚函数实现多态原理](https://blog.csdn.net/qq_24309981/article/details/89102183)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [C++虚函数多态实现](https://blog.csdn.net/qq_27576655/article/details/124535530)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值