所谓多态,简单来讲就是指,不同的子类在继承父类后分别都重写覆盖了父类的方法。
例如下例中:
class A { public:void f() { cout << "这是A中的func" << endl; }; };
class B: public A { public:void f() { cout << "这是B中的func" << endl; } };
如果我们调用 A a; a.f(); ,那么调用的就是A类中的f函数;如果我们调用 B b; b.f(); ,那么调用的就是B类中的f函数;如果我们调用 A a = B(); a.f(); ,结果也仍然会是调用A类中的f函数。
而有时候,一个基类会有很多派生类,这些派生类中也许会出现很多功能相似、名称相同的函数,如果手动去调用就会非常麻烦,我们希望的是能写一个函数,这个函数能统一帮我们调用传入对象中对应的那个函数,换句话来说,对于基类A的派生类BCDEF......如果存在那么一个函数,在我们想调用某个类中的某个同名函数时,能够自动帮我们对应到相应函数,也就是实现多态,就会方便很多。
这时就需要借助虚函数了。
虚函数,听这个名字就感觉它是虚的,事实上也可以这么理解,如果我们将基类中的一个同名函数定义为虚函数,那么,当使用基类引用或基类指针去调用派生类对象的同名函数时,它就会自动调用派生类中的同名函数。虽然这样说起来似乎是理所当然,毕竟调用的就是派生类中的函数,出现这样的结果似乎很好理解,但是注意,我们上述的例子已经表明,在没有定义虚函数的情况下,即使你使用基类引用或者基类指针,也调用不到派生类的同名函数,它能接触到的仅仅是基类的函数。
也就是说,虚函数只是提供了一个桥梁,当计算机通过基类指针或引用去调用这个函数,却发现它是虚函数时,它就会去检查是否在这个派生类中存在一个同名的函数,有就去调用它,所以可以说基类中的这个函数是被架空、覆盖的,一般不会被调用。
声明虚函数的关键字是 virtual ,注意,虚函数只需要在基类中声明就行了,派生类中的同名函数都不需要再声明。
我们来看下面这个例子:
#include <bits/stdc++.h> using namespace std; class A { public: virtual void f() { cout << "这是A中的func" << endl; }; }; class B: public A { public:void f() { cout << "这是B中的func" << endl; } }; class C: public B { public: void f() { cout << "这是C中的func" << endl; } }; void test_ref(A & a) { a.f(); } void test_ptr(A * a) { a->f(); } int main() { A a; B b; C c; a.f(); b.f(); c.f(); test_ref(a); test_ref(b); test_ref(c); test_ptr(&a); test_ptr(&b); test_ptr(&c); return 0; }
在上示代码中,我们将基类A中的f函数定义为虚函数,派生类B和C中也分别存在一个同名函数。然后我们定义了两个函数,这两个函数用来实现多态,它们一个使用基类指针调用f函数,一个使用基类引用调用,其结果都是一样的。在主函数中,我们先分别使用普通的对象调用方式调用一遍f函数,然后再使用函数调用。
运行结果为:
这是A中的func 这是B中的func 这是C中的func 这是A中的func 这是B中的func 这是C中的func 这是A中的func 这是B中的func 这是C中的func
从最后的结果可以看出,明明是同一个函数,传入不同类的对象,调用同一个函数,得到的结果却不一样,它自动对应到了相应的那个函数,显然比手动调用要方便很多。
最后,我们还要弄清楚一个区别,上面我们使用了基类指针和基类引用实现了虚函数的调用,那么问题就来了,能不能使用基类对象来调用虚函数。
其实这个问题的答案要看你是怎么理解的,通常来讲,我们调用虚函数是希望实现多态,但是,用基类对象能调用虚函数,无法实现多态。
例如,我们将上面的 test_ref 函数中的形参改为 A a ,然后再在主函数中分别传入类A B C的实例化对象a b c,结果为:
这是A中的func 这是A中的func 这是A中的func
也就是说,如果选择用基类对象调用虚函数,那么你永远只能调用到基类的虚函数,所以,调用是能调用的,只是没办法实现多态。
标签:调用,函数,派生类,多态,C++,func,基类 From: https://www.cnblogs.com/codas/p/17006183.html