C++进阶:详解多态(多态、虚函数、抽象类以及虚函数原理详解)
结束了继承的介绍:C++进阶:详细讲解继承
那紧接着的肯定就是多态啦
文章目录
1.多态的概念
多态是指同一个函数名可以根据调用对象的不同而具有不同的实现。它分为两种类型:编译时多态(静态多态)和运行时多态(动态多态)。
- 编译时多态: 通过函数重载和运算符重载实现,是在编译阶段确定函数调用。重载允许一个函数名有多个定义,编译器根据函数参数和上下文来选择正确的定义。
- 运行时多态: 通过虚函数和继承实现,是在运行阶段确定函数调用。运行时多态允许通过基类指针或引用来调用派生类的函数,实现了动态绑定。
2.多态的定义和实现
2.1多态的构成条件
多态的实现通常依赖于虚函数。在基类中声明虚函数,然后在派生类中进行重写(覆盖)。通过基类指针或引用调用虚函数时,将根据对象的实际类型调用相应的派生类函数
从上面这段话我们知道在继承中要构成多态还有两个条件:
必须通过基类的指针或者引用调用虚函数
被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写
class Person
{
public:
virtual void BuyTicket() { cout << "买票-全价" << endl; }//虚函数
};
class Child:public Person
{
public:
virtual void BuyTicket() { cout << "买票-半价" << endl; }//子类进行重写了
};
void test1()
{
Person* p = new Person;//基类的指针
p->BuyTicket();//调用BuyTicket
Child ch;
p = &ch;//现在基类的指针指向了子类
p->BuyTicket();
}
int main()
{
test1();
return 0;
}
2.2虚函数
2.2.1虚函数的概念
虚函数是在基类中使用
virtual
关键字声明的成员函数,它的存在允许在派生类中进行函数的重写(覆盖)。通过虚函数,可以实现运行时多态性
class Person
{
public:
virtual void BuyTicket() { cout << "买票-全价" << endl; }//虚函数
};
2.2.2虚函数的重写
虚函数的重写(Override)是指在派生类中重新实现(覆盖)了基类中已经声明为虚函数的函数。在进行函数重写时,子类中的虚函数的返回值类型、函数名、参数列表必须与基类中的虚函数完全相同
注意:在重写基类虚函数时,派生类的虚函数在不加virtual
关键字时,虽然也可以构成重写(因为继承后基类的虚函数被继承后在派生类依旧保持虚函数属性)但是该种写法不规范,大家还是少用为好。
2.2.3虚函数重写的两个例外
- 协变(基类与派生类虚函数返回值类型不同)
派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变
class A
{
public:
virtual A* f()
{
return new A;
}
};
class B:public A
{
public:
virtual B* f()
{
return new B;
}
};
- 析构函数的重写(基类与派生类的析构函数名字不同)
如果基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字,都与基类的析构函数构成重写,虽然基类与派生类析构函数名字不同。虽然函数名不相同,看起来违背了重写的规则,其实不然,这里可以理解为编译器对析构函数的名称做了特殊处