C++基础知识之"多态"

fengjingtu

问题引出

如果子类定义了与父类中原型相同的函数会发生什么?

函数重写:在子类中定义与父类中原型相同的函数,函数重写只发生在父类与子类之间

父类中被重写的函数依然会继承给子类
默认情况下子类中重写的函数将隐藏父类中的函数
通过作用域分辨符::可以访问到父类中被隐藏的函数

C/C++是静态编译型语言:在编译时,编译器自动根据指针的类型判断指向的是一个什么样的对象
1、在编译此函数的时,编译器不可能知道指针 p 究竟指向了什么。
2、编译器没有理由报错。
3、于是,编译器认为最安全的做法是编译到父类的print函数,因为父类和子类肯定都有相同的print函数。

面向对象新需求

如果我传一个父类对象,执行父类的print函数
如果我传一个子类对象,执行子类的printf函数

现象产生的原因
赋值兼容性原则遇上函数重写出现的一个现象
没有理由报错
对被调用函数来讲,在编译器编译期间,我就确定了,这个函数的参数是p,是Parent类型的。。。
静态链编

解决方案

C++中通过virtual关键字对多态进行支持
使用virtual声明的函数被重写后即可展现多态特性

多态实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <iostream>

using namespace std;
//赋值兼容性原则遇上函数重写(重写只发生在子类和父类之间)
class Parents
{
public:
void print()
{
cout << "I am parents" << endl;
}
virtual void print2()
{
cout << "I am 2 parents" << endl;
}
};
class Childs :public Parents
{
public:
void print()
{
cout << "I am childs" << endl;
}
virtual void print2()
{
cout << "I am 2 childs" << endl;
}

};
void printClass(Parents *p)
{
p->print();
}
void printClass2(Parents &p)
{
p.print();
}
//同样是这样两个函数,同样的p->print()语句,可以有不同的调用,根据对象不同,在子类和父类之间穿梭
void printClass3(Parents *p)
{
p->print2();
}
void printClass4(Parents &p)
{
p.print2();
}
void virtual_test1()
{

Childs c;
printClass(&c);//虽然传入的是子类,子类也有print函数,但是打印的是父类
printClass2(c);//因为继承调用了父类的函数,兼容也只能使用父类的函数。
//我们希望子类都已经重写了,就打印子类的!这种新需求需要使用多态来实现

printClass3(&c);
printClass4(c);
//使用vitual关键字来实现多态,这种方法会产品虚函数表,属于动态联编。
}



int main_virtual_test1()
{
virtual_test1();
cout << "Hello world!" << endl;
system("pause");
return 0;
}
//多态成立的三个条件:
//有继承
//有虚函数重写
//有兼容(父类指针指向子类对象)

多态的工程意义

面向对象3大概念

封装:突破了C语言函数的概念。。

继承:代码复用 。。。。我复用原来写好的代码。。。

多态:多态可以使用未来,写了一个框架,可以调用后来人,写的代码的能力

多态成立的条件

间接赋值成立的3个条件
1 定义两个变量。。。
2 建立关联 。。。。
3 *p

多态成立的三个条件
1 要有继承
2 要有函数重写(虚函数)
3 要有父类指针(父类引用)指向子类对象
多态是设计模式的基础,多态是框架的基础

多态的理论基础

静态联编和动态联编
联编是指一个程序模块、代码之间互相关联的过程。

静态联编(static binding),是程序的匹配、连接在编译阶段实现,也称为早期匹配。
重载函数使用静态联编。

动态联编是指程序联编推迟到运行时进行,所以又称为晚期联编(迟绑定)。
switch 语句和 if 语句是动态联编的例子。

C++与C相同,是静态编译型语言
在编译时,编译器自动根据指针的类型判断指向的是一个什么样的对象;所以编译器认为父类指针指向的是父类对象。
由于程序没有运行,所以不可能知道父类指针指向的具体是父类对象还是子类对象,从程序安全的角度,编译器假设父类指针只指向父类对象,因此编译的结果为调用父类的成员函数。这种特性就是静态联编。