一、 多态是什么?
通俗点说,就是多种形态。具体点就是不同对象完成某种事情,会产生不一样的状态。
举个例子:就好比:买票的时候,普通人、学生、军人等等,他们买票有不同的结果,普通人全价票,学生享受学生价的票,军人有优先购票以及军人的票价。
二、 多态的实现
1、构成多态有两个条件:
(1)必须是基类的指针或者基类的引用调用虚函数。
(2)被调用的函数必须是虚函数,并且派生类必须对基类的虚函数进行重写。(有两个特殊)
简单点说就是:1. 虚函数重写 2. 父类指针或者引用去调用虚函数
2、什么是虚函数?
虚函数就是在成员函数前面加 virtual 修饰
3、虚函数重写/覆盖条件:
(1)虚函数 + 三同(函数名,参数,返回值)
(2)不符合重写,就是隐藏关系
注意:(两个特殊)
(1)子类虚函数不加 virtual 依旧构成重写(最好加上)
(2)重写的协变。返回值可以不同,要求必须是父子关系的指针或者引用
下面用代码看一下,如下:
class Person {
public:
virtual void BuyTicket() { cout << "买票全价" << endl; }
};
class Student : public Person
{
public:
virtual void BuyTicket() { cout << "买票半价" << endl; }
};
class Soldier : public Person
{
public:
virtual void BuyTicket() { cout << "买票优先" << endl; }
};
//void Func(Person p) // 不是父类的指针或者引用就不是多态
void Func(Person& p)
{
p.BuyTicket();
}
int main()
{
Person p;
Student st;
Soldier so;
Func(p);
Func(st);
Func(so);
return 0;
}
运行之后,结果如下:
上面运行结果可以看出来,不同的对象传给父类的引用,所调的函数是不一样的。
4 . 下面我打破多态的两个条件看一下。如下:
(1)打破父类的指针或者引用
我将引用改为普通对象调用,看一下结果如何,如下:
void Func(Person p) // 不是父类的指针或者引用就不是多态
//void Func(Person& p)
{
p.BuyTicket();
}
运行结果如下:
修改之后,结果都掉的是 Person 的成员函数,为什么?因为修改之后就是普通调用了(具体细节我在下一篇文章细讲)
(2)打破重写的条件(重写:虚函数 + 三同)
① 我将父类中的虚函数去掉,如下:
class Person {
public:
//virtual void BuyTicket() { cout << "买票全价" << endl; }
void BuyTicket() { cout << "买票全价" << endl; }
};
运行结果如下:
也是如此,结果都是调用父类的方法。
② 去掉三同中的函数名相同,这里我将三个函数名都改为不一样,如下:(如果改一个,那么其他两个还是相同,结果是各自的成员函数打印出来的结果)
class Person {
public:
virtual void BuyTicket() { cout << "买票全价" << endl; }
//void BuyTicket() { cout << "买票全价" << endl; }
};
class Student : public Person
{
public:
virtual void Buy() { cout << "买票半价" << endl; }
};
class Soldier : public Person
{
public:
virtual void BuyTi() { cout << "买票优先" << endl; }
};
运行结果如下:
5. 下面解释一下两个特例
(1)子类虚函数不加 virtual 依旧构成重写(最好加上)
(2)重写的协变。返回值可以不同,要求必须是父子关系的指针或者引用
先解释(1),如下:
我将 student、soldier 的成员函数的 virtual 去掉了,那么这两个成员函数就不是虚函数了吧?
那么结果怎么样?如下:
class Person {
public:
virtual void BuyTicket() { cout << "买票全价" << endl; }
//void BuyTicket() { cout << "买票全价" << endl; }
};
class Student : public Person
{
public:
//virtual void BuyTicket() { cout << "买票半价" << endl; }
void BuyTicket() { cout << "买票半价" << endl; }
};
class Soldier : public Person
{
public:
//virtual void BuyTicket() { cout << "买票优先" << endl; }
void BuyTicket() { cout << "买票优先" << endl; }
};
运行结果如下:
运行结果还是各自的方法,为什么?
因为子类继承父类之后,将父类的虚函数继承下来了,重写了父类的方法,简单点说就是,子类继承之后,子类中也有一样的虚函数,但是虚函数的实现依然是子类的。
最后解释(2),如下:
虽然返回值可以同,但是必须是父子关系的指针或者引用,我这里就用引用解释一下,如下:
class Person {
public:
virtual Person& BuyTicket()
{
cout << "买票全价" << endl;
return *this;
}
};
class Student : public Person
{
public:
virtual Student& BuyTicket()
{
cout << "买票半价" << endl;
return *this;
}
};
class Soldier : public Person
{
public:
virtual Soldier& BuyTicket()
{
cout << "买票优先" << endl;
return *this;
}
};
运行结果如下: