多态
多态是C++面向对象的三大特性之一
多态分为两种:
- 静态多态:重载—函数重载与运算符重载
- 动态多态:派生类和虚函数
静态多态与动态多态的区别:函数地址的绑定时机不同
- 静态多态的函数地址早绑定,即在编译阶段确定函数地址
- 动态多态的函数地址晚绑定,即在运行阶段确定函数地址
#include <iostream>
using namespace std;
class A
{
public:
virtual void speak()
{
cout << "A::speak" << endl;
}
};
class B : public A
{
public:
void speak()
{
cout << "B::speak" << endl;
}
};
class C : public A
{
public:
void speak()
{
cout << "C::speak" << endl;
}
};
// 父类的引用指向子类的对象
// 地址早绑定,在编译阶段确定函数地址
void doTest(A &a)
{
a.speak();
}
void Test()
{
B b;
doTest(b);
C c;
c.speak();
}
int main()
{
Test();
system("pause");
return 0;
}
动态多态的满足条件
-
具有继承关系
-
子类必须重写父类的虚函数
重写:函数名,参数个数,类型,顺序必须完全相同
动态多态的使用
- 父类的指针或者引用指向子类对象
多态的原理
由于写了一个虚函数,类内部结构发生改变,多了一个虚函数指针(vfptr),虚函数指针指向一个虚函数表(vftable),当子类自己重写虚函数后,会替换子类自己的虚函数表里的内容 ,当用父类的引用指向子类对象,由于本身还是一个子类对象,所以当子类调用speak函数时候,会从子类的虚函数表中找函数入口地址。
工具支持:Developer Command Prompt for VS 2019
class A
{
public:
void speak()
{
cout << "A::speak" << endl;
}
};
class A
{
public:
virtual void speak()
{
cout << "A::speak" << endl;
}
};
B没有重写A中speak函数
class A
{
public:
virtual void speak()
{
cout << "A::speak" << endl;
}
};
class B : public A
{
};
B重写A中speak函数
class A
{
public:
virtual void speak()
{
cout << "A::speak" << endl;
}
};
class B : public A
{
public:
void speak()
{
cout << "B::speak" << endl;
}
};
纯虚函数和抽象类
在多态中,通常父类中的虚函数实现是毫无意义的,主要是调用子类中的重写的内容
因此可以将虚函数改为纯虚函数
纯虚函数语法:
virtual 返回值类型 函数名 (参数列表)=0;
当类中有了纯虚函数,这个类也称为抽象类
抽象类特点:
- 无法实例化对象
数和抽象类
在多态中,通常父类中的虚函数实现是毫无意义的,主要是调用子类中的重写的内容
因此可以将虚函数改为纯虚函数
纯虚函数语法:
virtual 返回值类型 函数名 (参数列表)=0;
当类中有了纯虚函数,这个类也称为抽象类
抽象类特点:
- 无法实例化对象
- 子类必须重写抽象类中的纯虚函数,否则也属于抽象类
#include <iostream>
using namespace std;
//抽象类
class A
{
public:
//纯虚函数
//只要有一个纯虚函数,则个类称为抽象类
// 抽象类特点:
// 1.无法实例化兑现
// 2.抽象类的子类必须重写父类中的纯虚函数,否则也属于抽象类
//
virtual void speak() = 0;
};
class B :public A
{
public:
virtual void speak()
{
cout << "B::speak" << endl;
}
};
void Test01()
{
//报错 :
// 不允许使用抽象类类型“A”的对象:
// 函数“A.speak”是纯虚拟函数
//A a;
//new A;
}
void Test02()
{
//B中没有重写speak函数时,如果创建对象,则会报错。
//不允许使用抽急类类型“B”的对象:
//纯虚拟 函数“A : speak”没有强制替代项
//重写之后
B b;
B* bb = new(B);
bb->speak();
}
int main()
{
system("pause");
return 0;
}