C++多态

来源:互联网 发布:苹果数据接口转usb 编辑:程序博客网 时间:2024/06/05 23:05

C++多态

多态是C++三大特性之一。 
简单来说多态就像是“一个接口,多种形态”。多态根据函数地址绑定的先后次序可以分为静态多态和动态多态

静态多态:函数的调用是在编译期间完成的(静态绑定。函数重载)。 
动态多态:函数的调用时在程序运行期间完成的(动态绑定。函数重写)

要实现动态绑定,要有两个条件。

1、必须是虚函数。 
2、通过基类类型的指针或引用调用虚函数。

先来看看什么是虚函数:用关键字virtual修饰的函数叫虚函数(有的函数不能定义为虚函数)。

刚在动态多态里说动态绑定实际上就是函数重写。 
重写规则:一定是虚函数,并且一个在基类中,另一个在派生类中。重写要保证函数的原型(返回值、函数名、参数列表)一致(协变除外,协变是基类返回的是基类的引用或指针,而在派生类中返回的是派生类的指针或引用)。

1.class Base
2.{
3.public:
4. virtual void Funtest()
5. {}
6.};
7.
8.class Derived: public Base
9.{
10.public:
11. virtual void Funtest()
12.};

这个就是简单的函数重写。刚刚提到不是所有的函数都可以进行重写,在这里提一下。构造函数、拷贝构造、静态函数、友元函数都不可以重写(即定义为虚函数)。析构函数和赋值运算符重载可以重写(但最好不要将赋值运算符重载设为虚函数。而最好将基类的析构函数设为虚函数); 
有一类虚函数叫纯虚函数,纯虚函数是在虚函数的形参后面写上=0,那么这个函数就定义为了纯虚函数,把包含纯虚函数的类叫做抽象类。简单来说就是抽象类也不知道自己要执行具体的什么功能。而抽象类不能够实例化一个对象,只有这个抽象类被继承下去时,派生类才能实例化出对象

1.class A
2.{
3.public:
4. virtual void Funtest() = 0
5. {
6. cout<<"Funtest()"<<endl;
7. }
8.};
9.
10.class B:public A
11.{
12.public:
13. virtual void Funtest()
14.
{
15. cout<<"B::Funtest()"<<endl;
16. }
17.};
18.
19.int main ()
20.
{
21. A a;
22. B b;
23. return 0;
24.}

这里在A中定义了一个纯虚函数Funtest(),然后通过B类继承下来,在main里用A和B分别实例化一个对象。

 
在编译期间报错,提示抽象的类不能实例化出对象。

现在来详细看一下具体多态实现中都有什么类型

1.class Base
2.{
3.public:
4. virtual void Display()//基类是虚函数,派生类继承下来也是虚函数
5.
{
6. cout<<"Base::Display()"<<endl;
7. }
8.
9. virtual void Display()//基类是虚函数,派生类继承不是虚函数
10.
{
11. cout<<"Base::Display()"<<endl;
12. }
13.
14. virtual void Display(int a)//基类虚函数是一个有int类型的参数,派生类虚函数有一个char类型的参数
15.
{
16. cout<<"Base::Display(int a)"<<endl;
17. }
18.
19. void Display()//基类不是虚函数,派生类是虚函数
20.
{
21. cout<<"Base::Display()"<<endl;
22. }
23.
24. void Display()//基类不是虚函数,派生类也不是虚函数
25.
{
26. cout<<"Base::Display()"<<endl;
27. }
28.
29. virtual char Display()//基类是一个返回类型为char类型的虚函数,派生类的返回类型是int型的
30.
{
31. cout<<"Base::Display()"<<endl;
32. return 1;
33. }
34.
35. virtual Base& Display()//基类返回类型为Base&的,派生类返回值为Derive&的
36.
{
37. cout<<"Base::Display()"<<endl;
38. return *this;
39. }
40.
41.};
42.
43.class Derived: public Base
44.{
45.public:
46. virtual void Display()
47.
{
48. cout<<"Derived::Display()"<<endl;
49. }
50.
51. void Display()
52.
{
53. cout<<"Derived::Display()"<<endl;
54. }
55.
56. virtual void Display(char a)
57.
{
58. cout<<"Derived::Display(char a)"<<endl;
59. }
60.
61. virtual void Display()
62.
{
63. cout<<"Derived::Display()"<<endl;
64. }
65.
66. void Display()
67.
{
68. cout<<"Derived::Display()"<<endl;
69. }
70.
71. virtual int Display()
72.
{
73. cout<<"Display()"<<endl;
74. return 1;
75. }
76.
77. virtual Derived& Display()
78.
{
79. cout<<"Derived::Display()"<<endl;
80. return *this;
81. }
82.};
83.
84.void test(Base& b)
85.
{
86. b.Display();
87.}
88.
89.
90.int main()
91.
{
92. Base b;
93. Derived d;
94. test(b);
95. test(d);
96. system("pause");
97. return 0;
98.}

先具体的看一下哪种能够实现多态,哪种不能实现多态。 
1、基类是虚函数,派生类继承下来也是虚函数

 
这种可以实现多态

2、基类是虚函数,派生类继承不是虚函数

 
这种也可以实现多态

3、基类虚函数是一个有int类型的参数,派生类虚函数有一个char类型的参数

 
这种不构成多态,不满足重写规则

4、基类不是虚函数,派生类是虚函数

 
这种不可以实现多态(基类不必须是虚函数)

5、基类不是虚函数,派生类也不是虚函数

 
这种也不可以实现多态(和上面原因一样)

6、基类是一个返回类型为char类型的虚函数,派生类的返回类型是int型的

 
这种系统会报错,提示既不相同也不协变

7、基类返回类型为Base&的,派生类返回值为Derive&的

 
这种可以实现多态(返回值类型分别为基类和派生类的引用或指针,叫做协变)

主要看一下最后两种,当返回值类型不一样时,若返回的是对应类的指针或引用时会协变的,协变是可以实现多态的。否则就既不相同也不协变。