通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同 的状态。
多态的定义以及实现1.多态定义的构成条件
(1)调用函数的对象必须是指针或者引用
(2)被调用的函数必须是虚函数,且完成了虚函数的重写
什么是虚函数?
就是在类的成员函数的前面加virtual关键字
什么是虚函数的重写?
派生类中有一个跟基类的完全相同虚函数,我们就称子类的虚函数重写了基类的虚函数,完全相同是指:函数名、参数、返回值都相同。另外虚函数的重写也叫作虚函数的覆盖。
class Person
{
public:
virtual void BuyTicket()
{
cout << "买票-全价" << endl;
}
};
class Student : public Person
{
public:
virtual void BuyTicket()
{
cout << "买票-半价" << endl;
}
};
void Func(Person& p)
{
p.BuyTicket();
}
int main()
{
Person ps;
Student st;
Func(ps);
Func(st);
return 0;
}
虚函数重写的例外:协变(作为了解)
虚函数重写有一个例外:重写的虚函数的返回值可以不同,但是必须分别是基类指针和派生类指针或者基类引用和派生类引用。
不规范的重写行为
在派生类中重写的成员函数可以不加virtual关键字,也构成重写的,因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数的属性,我们只是重写了他。但是这是非常不规范的,我们平时不要这样做。
class Person
{
public:
virtual void BuyTicket()
{
cout << "买票-全价" << endl;
}
};
class Student : public Person
{
public:
void BuyTicket()
{
cout << "买票-半价" << endl;
}
};
析构函数的重写问题
基类中的析构函数如果是虚函数,那么派生类的析构函数就重写了基类的析构函数。这里他们的函数名不相 同,看起来违背了重写的规则,其实不然,这里可以理解为编译器对析构函数的名称做了特殊处理,编译后 析构函数的名称统一处理成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;
}
接口继承和实现继承
普通函数的继承是一种实现继承,派生类继承了基类函数,可以使用函数,继承的是函数的实现。虚函数的继承是一种接口继承,派生类继承的是基类虚函数的接口,目的是为了重写,达成多态,继承的是接口。所 以如果不实现多态,不要把函数定义成虚函数
重载,覆盖(重写),隐藏(重定义)的对比
抽象类纯虚函数:在虚函数的后面写上 =0 ,则这个函数为纯虚函数。
纯虚函数规范了派生类必须重写,另外纯虚函数更体现出了接口继承。
class Car
{
public:
virtual void Drive() = 0;//虚函数
};
class Benz :public Car
{
public:
virtual void Drive()
{
cout << "Benz-舒适" << endl;
}
};
class BMW :public Car
{
public:
virtual void Drive()
{
cout << "BMW-操控" << endl;
}
};
void Test()
{
Car* pBenz = new Benz;
pBenz->Drive();
Car* pBMW = new BMW;
pBMW->Drive();
}
class Car
{
public:
virtual void Drive(){}
};
// 2.override 修饰派生类虚函数强制完成重写
class Benz :public Car
{
public:
virtual void Drive() override
{
cout << "Benz-舒适" << endl;
}
};
c++中的override和final
C++11提供override 和 final 来修饰虚函数。
实际中我们建议多使用纯虚函数+ overrid的方式来强制重写虚函数,因为虚函数的意义就是实现多态,如果 没有重写,虚函数就没有意义
// 1.final 修饰基类的虚函数不能被派生类重写
class Car
{
public:
virtual void Drive() final {}
};
class Benz :public Car
{
public:
virtual void Drive()
{
cout << "Benz-舒适" << endl;
}
};
class Car
{
public:
virtual void Drive(){}
};
// 2.override 修饰派生类虚函数强制完成重写,如果没有重写会编译报错
class Benz :public Car
{
public:
virtual void Drive() override
{
cout << "Benz-舒适" << endl;
}
};