什么是多态
🌮 多态是面向对象编程中的一个特性,它允许不同的对象对同一消息做出不同的响应。简单来说,多态是一种允许用一个统一的接口来表示不同类型对象的能力。通过多态,可以在不需要知道对象的具体类型的情况下,调用对象的方法,实现代码的灵活性和可扩展性。
🌮 在多态中,父类可以被子类所继承,而子类可以重写父类的方法,并根据自己的需求为这些方法提供不同的实现。当使用父类的引用指向子类的对象时,可以根据实际的对象类型来调用相应的方法,即使引用的类型是父类,但最终执行的是子类中重写的方法。
🌮 多态可以通过继承和重写方法来实现,也可以通过接口来实现。它能够提高代码的可读性和可维护性,减少代码的重复性,并且能够在运行时动态地确定对象的实际类型,从而实现不同类型对象的不同行为。
用一句话来说就是:一个动作让不同对象做有不同的结果
多态的定义以及实现
多态的实现就两个核心条件:
1、子类完成虚函数的重写
2、父类的指针或者引用进行操作
class Person {
public:
virtual void BuyTicket() { cout << "买票-全价" << endl; }
};
class Student : public Person {
public:
virtual void BuyTicket() { cout << "买票-半价" << endl; }
/*注意:在重写基类虚函数时,派生类的虚函数在不加virtual关键字时,虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使用*/
/*void BuyTicket() { cout << "买票-半价" << endl; }*/
};
void Func(Person& p)
{
p.BuyTicket();
}
int main()
{
Person ps;
Student st;
Func(ps);
Func(st);
return 0;
}
//如果不满足多态,调用的时候就看类型。
//如果满足多态,看指向的对象是谁。
除此之外虚函数还有两个意外:
1. 协变(基类与派生类虚函数返回值类型不同)
//派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指
//针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。(了解)
class A {};
class B : public A {};
class Person {
public:
virtual A* f() { return new A; }
};
class Student : public Person {
public:
virtual B* f() { return new B; }
};
返回值可以不同,但是必须要是父子关系的指针或者引用。这个你可以叫做父子协变。只要是父子关系就行了,不硬性要求是哪里的父子关系
//2. 析构函数的重写(基类与派生类析构函数的名字不同)
//如果基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字,
//都与基类的析构函数构成重写,虽然基类与派生类析构函数名字不同。虽然函数名不相同,
//看起来违背了重写的规则,其实不然,这里可以理解为编译器对析构函数的名称做了特殊处理,编译后析构函数的名称统一处理成destructor。
class Person {
public:
virtual ~Person() { cout << "~Person()" << endl; }
};
class Student : public Person {
public:
virtual ~Student() { cout << "~Student()" << endl; }
};
// 只有派生类Student的析构函数重写了Person的析构函数,下面的delete对象调用析构函
数,才能构成多态,才能保证p1和p2指向的对象正确的调用析构函数。
int main()
{
Person* p1 = new Person;
Person* p2 = new Student;
delete p1;
delete p2;
return 0;
}
抽象类:
class a
{
public:
virtual void test()=0;
}
虚函数后面直接跟关键字=0就是纯虚函数,含有纯函数的类就是抽象类。该类无法实例化对象,如果子类想要有对象,那么就必须完成重写,这种方法很好的体现了接口继承。
静态成员函数不能被virtual、const、volatile
为何static成员函数不能为virtual
1. static成员不属于任何类对象或类实例,所以即使给此函数加上virutal也是没有任何意义的。
2. 静态与非静态成员函数之间有一个主要的区别。那就是静态成员函数没有this指针。
虚函数依靠vptr和vtable来处理。vptr是一个指针,在类的构造函数中创建生成,并且只能用this指针来访问它,因为它是类的一个成员,并且vptr指向保存虚函数地址的vtable.
对于静态成员函数,它没有this指针,所以无法访问vptr. 这就是为何static函数不能为virtual.
虚函数的调用关系:this -> vptr -> vtable ->virtual function
不能用const是因为static成员函数根本就没有this指针,所以const没有意义,volatile同理。