首先介绍一下多态的概念:
C++支持两种多态性,分别是编译时和运行时。在编译时就确定的函数调用称为静态联编,它通过使用函数重载,模板等实现的。在运行时才确定的函数调用称为动态联编,它通过虚函数来实现的。虚函数的声明方式是在函数原型上加关键字virtual,在基类中含义虚函数,在派生类中的函数不需要显示地写出virtual关键字。
多态的一般使用方法:声明基类的指针,利用该指针指向任意一个子类对象,调用相应的虚函数,可以根据指向的子类的不同而实现不同的方法。如果没有使用虚函数的话,即没有利用C++多态性,则利用基类指针调用相应的函数的时候,将总被限制za9基类函数本身,而无法调用到子类中被重写过的函数。
#include<iostream>
using namespace std;
class A
{
public:
void foo()
{
printf("1\n");
}
virtual void fun()
{
printf("2\n");
}
};
class B : public A
{
public:
void foo()
{
printf("3\n");
}
void fun()
{
printf("4\n");
}
};
int main(void)
{
A a;
B b;
A *p = &a;
p->foo();//1
p->fun();//2
p = &b;
p->foo();//1
p->fun();//4
cout << "********" << endl;
B *ptr = (B*)&a;
ptr->foo();//3
ptr->fun();//2
return 0;
}
第一个p->foo()和p->fuu()都很好理解,本身是基类指针,指向的又是基类对象,调用的都是基类本身的函数,因此
输出结果就是1、2。第二个输出结果就是1、4。p->foo()和p->fuu()则是基类指针指向子类对象,正式体现多态的用法,
p->foo()由于指针是个基类指针,指向是一个固定偏移量的函数,因此此时指向的就只能是基类的foo()函数的代码了,
因此输出的结果还是1。而p->fun()指针是基类指针,指向的fun是一个虚函数,由于每个虚函数都有一个虚函数列表,
此时p调用fun()并不是直接调用函数,而是通过虚函数列表找到相应的函数的地址,因此根据指向的对象不同,函数地址
也将不同,这里将找到对应的子类的fun()函数的地址,因此输出的结果也会是子类的结果4。
笔试的题目中还有一个另类测试方法。即
B *ptr = (B *)&a; ptr->foo(); ptr->fun();
问这两调用的输出结果。这是一个用子类的指针去指向一个强制转换为子类地址的基类对象。这两句调用的输出结果
是3,2.
利用下面的规则可以很方便地得出上面的结果:
主要涉及到两类多态的问题,一个是编译时多态,一个是运行时多态,non-virtual函数是执行的编译时多态,virtual是运行
时多态。 对non-virtual成员函数的调用由指针/引用的类型决定,而virtual 成员函数则有赋值类型决定。