多态——多种形态
多态的分类:
1.静态多态:函数重载和运算符重载(复用函数名)
2.动态多态:派生类和虚函数实现运行时多态
静态多态和动态多态的区别:
静态多态的函数地址早绑定——编译阶段确定函数地址
动态多态的函数地址晚绑定——运行阶段确定函数地址
另一种分类:
1.重载多态--函数重载&运算符重载
2.包含多态--virtual
3.强制多态--强制类型转换 _cast
4.参数多态--模板
地址早绑定和晚绑定
下面代码中父类:Animal,成员函数:speak,子类:Cat,成员函数:speak;
函数地址早绑定:
先使用父类的构造函数,输出animal speak。
class Animal
{
public:
void speak(){ cout << "animal speak" << endl; }
};
class Cat :public Animal
{
public:
void speak() { cout << "cat speak" << endl; }
};
void doSpeak(Animal &animal)
{
animal.speak();
}
int main1()
{
Cat cat;
doSpeak(cat);//animal speak
//父子之间允许类型转换,函数地址早绑定
return 0;
}
函数地址晚绑定:
父类中使用虚函数,子类重写speak函数覆盖,输出cat speak。
实现动态多态:
1.有继承关系
2.子类要重写(函数返回值类型、名称、参数列表都相同)父类的虚函数
动态多态的使用:父类的 指针 或者 引用 执行子类对象!!!
子类将父类的虚函数表继承下来,如果子类重写了这个虚函数,则会将之前的虚函数覆盖,但父类自己的没有改变,当父类的指针或引用指向子类对象时,发生多态。
如果是基类同名同参的虚函数,则子类中可以不用写virtual。
class Animal
{
public:
virtual void speak() { cout << "animal speak" << endl; }//加一个虚的关键字
};
class Cat :public Animal
{
public:
void speak() { cout << "cat speak" << endl; }
};
void doSpeak(Animal &animal)
{
animal.speak();
}
int main()
{
Cat cat;
doSpeak(cat);//cat speak
return 0;
}
虚表
类中如果有虚函数,则会有一个(继承来的会有多个)vfptr虚函数指针。
如果是个空类,则大小为1个字节:占位。
在不算继承的情况下,如果里面只有虚函数(无论多少个),则为四个字节,一个指针的大小。指针指向一个虚表,虚表里面放着虚函数的入口地址。
class A
{
public:
virtual void fa() { cout << "A::fa" << endl; }
virtual void ga() { cout << "A::ga" << endl; }
virtual void ha() { cout << "A::ha" << endl; }
private:
int m_i;
int m_j;
};
int main()
{
A a;
}
且其他成员地址都在虚表之后
可以把这个虚表看作是函数指针数组,可以定义一个函数指针指向这个数组,
int main()
{
A a;
typedef void (*Fun)();//函数指针
Fun pf = NULL;
pf = (Fun) * ((int*)*(int*)(&a));
pf(); //A::fa
pf = (Fun) * ((int*)*(int*)(&a) + 1);
pf();//A::fb
pf = (Fun) * ((int*)*(int*)(&a) + 2);
pf();//A::fc
}
类的地址第一个内容就是这个虚表地址:(int*)(&a),//如果不强转的话&a是a*类型的
fa的地址为虚表第一个元素(解引用):(int*)*(int*)(&a),
最后再解引用就是fa函数:*((int*)*(int*)(&a))
之后转成函数指针类型:(Fun)*((int*)*(int*)(&a))
就可以用函数指针调用虚函数了
虚表的个数
对于多继承,每个父类有自己的虚表。子类将新的虚函数放到第一个父类的虚表中。
下面A有一个虚指针,B有一个虚指针,C有一个虚指针,D继承了ABC的虚指针,并将自己独有的虚函数地址放在继承下来的A的虚表中
class A
{
public:
virtual void fa() { cout << "A::fa" << endl; }
virtual void ga() { cout << "A::ga" << endl; }
};
class B
{
public:
virtual void fb() { cout << "B::fb" << endl; }
virtual void gb() { cout << "B::gb" << endl; }
};
class C
{
public:
virtual void fc() { cout << "C::fc" << endl; }
virtual void gc() { cout << "C::gc" << endl; }
};
class D :public A, public B, public C
{
public:
virtual void fd() { cout << "D::fd" << endl; }
virtual void gd() { cout << "D::gd" << endl; }
};
void main()
{
D d;
cout << sizeof(D) << endl;//12,继承了三个虚指针,修改了第一个
typedef void (*Fun)();
Fun pf = (Fun) * ((int*)(*(int*)(&d)) + 1);
pf();//A::ga
pf = (Fun) * ((int*)(*(int*)(&d)) + 2);
pf();//D::fd
pf = (Fun) * ((int*)(*(int*)(&d)) + 3);
pf();//D::gd
}