0%

c++ - 多态

最近在学习 C++,所以顺便将每日所学记录下来,一方面为了巩固学习的知识,另一方面也为同样在学习C++的童鞋们提供一份参考。

多态

多态条件

多态是在不同继承关系的类对象,去调同一函数,产生了不同的行为。

就是说,有一对继承关系的两个类,这两个类里面都有一个函数且名字、参数、返回值均相同,然后我们通过调用函数来实现不同类对象完成不同的事件。

多态成立条件:

  • 必须存在继承
  • 必须存在函数重写
  • 要有基类指针指向子类对象
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
73
74
75
76
77
78
#include <iostream>

using namespace std;
//定义一个子类和父类
class Parent
{
public:

Parent(int a = 0)
{
this->a = a;
}
virtual void Print()
{
cout << "父类:" << a << endl;
}
protected:
private:
int a;
};

class Child : public Parent
{
public:
Child(int b = 0)
{
this->b = b;
}
virtual void Print()
{
cout << "子类:" << b << endl;
}

protected:
private:
int b;
};


void HowToPrint1(Parent *p)
{
p->Print();
}

void HowToPrint2(Parent &myp)
{
myp.Print();
}
int main()
{
Parent p1(1);
Child c1(0);
/*
p1.Print();
c1.Print();


//赋值兼容
Parent *p = NULL;
p = &p1;
p->Print();

p = &c1;
p->Print(); //两个同名函数,子类对象赋值给父类



Parent &p2 = c1;
p2.Print();
*/
HowToPrint1(&p1);
HowToPrint1(&c1);
HowToPrint2(p1);
HowToPrint2(c1);

system("pause");
return 0;
}

多态案例

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
#include <iostream>
using namespace std;


class DuckBase
{
public:
virtual void Cry() = 0; //鸭子叫的行为
};

class SmallDuck : public DuckBase
{
void Cry()
{
cout << "我是一只小鸭子,嘎嘎嘎" << endl;
}
};

class BigDuck : public SmallDuck
{
void Cry()
{
cout << "我是一只大鸭子,嘎嘎嘎" << endl;
}
};


class WoodDuck : public BigDuck
{
void Cry()
{
cout << "我是一只木鸭子,嘎嘎嘎" << endl;
}
};

void Cry(DuckBase *Duck)
{
Duck->Cry();
}

int main()
{
SmallDuck s;
BigDuck b;
WoodDuck w;
Cry(&s);
Cry(&w);
Cry(&b);
system("pause");
return 0;
}

重写重定义重载的区别

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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include <cstdlib>
#include <iostream>

using namespace std;

class Parent01
{
public:
Parent01()
{
cout<<"Parent01:printf()..do"<<endl;
}
public:
void func()
{
cout<<"Parent01:void func()"<<endl;
}

void abcd()
{
cout<<"Parent01:void func()"<<endl;
}

virtual void func(int i)
{
cout<<"Parent:void func(int i)"<<endl;
}

virtual void func(int i, int j)
{
cout<<"Parent:void func(int i, int j)"<<endl;
}
};


//重写的两种情况
//如果函数重写,在父类中增加了virtual关键字, 将能产生多态。。。。
//如果函数重写,没有加virtual关键字,,相当于在子类中重定义。。。。。,不会发生多态。。。
class Child01 : public Parent01
{

public:

//原因是发生了 名称覆盖,把子类中的没有函数参数的,这个函数abcd名称覆盖了。。。
//在子类中,是不能重载父类的函数的。编译器就是这么做的,顺从。。。。
void abcd(int a, int b)
{
cout<<"Parent01:void func()"<<endl;
}

//此处2个参数,和子类func函数是什么关系
void func(int i, int j)
{
cout<<"Child:void func(int i, int j)"<<" "<<i + j<<endl;
}

//此处3个参数的,和子类func函数是什么关系
void func(int i, int j, int k)
{
cout<<"Child:void func(int i, int j, int k)"<<" "<<i + j + k<<endl;
}
};

void run01(Parent01* p)
{
p->func(1, 2);
}

int main()
{
Parent01 p;

p.func();
p.func(1);
p.func(1, 2);


Child01 c;
//c.Parent01::abcd(); //这个函数是从父类中继承而来 可以使用。。。
//子类和父类有相同的名字(变量名字或者是函数名字的时,子类名字覆盖父类名字,如果想使用父类的资源,需要加::)
c.Parent01::func(); //问题1 这个函数是从父类中继承而来,为什么这个地方不能使用
//c.func(); //问题1
//c.func(1, 2);
/*
run01(&p);
run01(&c);
*/
system("pause");
return 0;
}

//问题1:child对象继承父类对象的func,请问这句话能运行吗?why
//c.func();

//1子类里面的func无法重载父类里面的func
//2当父类和子类有相同的函数名、变量名出现,发生名称覆盖
//3//c.Parent::func();
//问题2 子类的两个func和父类里的三个func函数是什么关系?


函数重载:

  • 函数重载必须在同一个类中
  • 子类无法继承父类的函数,父类同名函数将被名称覆盖
  • 重载是在编译期间根据参数类型和个数决定函数调用

函数重写:

  • 必须发生在父类与子类之间
  • 父类与子类中的函数必须有完全相同的类型
  • 使用virtual声明之后能够产生多态(如果不适用virtual,那叫重定义)
  • 多态是在运行期间根据具体对象的类型决定函数调用

多态实现原理

  • 当类中声明虚函数时,编译器回在类中生成一个虚函数表
  • 虚函数表是一个存储类成员函数指针的数据结构
  • 虚函数表是由编译器自动生成和维护的
  • virtual成员函数回被编译器放入虚函数表中
  • 存在虚函数是,每个对象中都有一个纸箱虚函数表的指针(vptr指针)

vptr指针存在

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
73
74
75
76
77
78
79
80
81
82
#include <iostream>
using namespace std;

class AA
{
public:
AA()
{
;
}
~AA()
{
;
}

void Print()
{
printf("我是爷爷\n");
}
private:
protected:

};

class BB : public AA
{
public:
BB()
{
;
}
~BB()
{
;
}
void Print()
{
printf("我是爸爸\n");
}

};



class CC : public BB
{
public:
CC()
{
;
}
~CC()
{
;
};
virtual void Print() //多态函数
{
printf("我是孙子\n");
}

};


void Print(AA *a)
{
a->Print();
}


void main()
{
AA a;
BB b;
CC c;
Print(&a);
Print(&b);
Print(&c);
printf("sizeof = %d\n", sizeof(AA)); //1字节
printf("sizeof = %d\n", sizeof(BB)); //1字节
printf("sizeof = %d\n", sizeof(CC)); //4字节 存在vptr指针
system("pause");
}

纯虚函数

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
#include <iostream>
using namespace std;

class figure
{
public:
virtual int showarea() = 0;
};

class Tri : public figure
{
public:
Tri(int a = 0, int b = 0)
{
this->a = a;
this->b = b;
}
virtual int showarea()
{
cout << "三角形s" << a*b / 2 << endl;
return 0;
}
private:
int a;
int b;
};

class Squre : public figure
{
public:
Squre(int a = 0, int b = 0)
{
this->a = a;
this->b = b;
}
virtual int showarea()
{
cout << "四边形s" << a*b << endl;
return 0;
}
private:
int a;
int b;
};

void Print(figure *p)
{
p->showarea();
}

void main()
{
figure *pBase = NULL;
Tri t(10, 2);
Print(&t);
//t.showarea();
Squre s(10,20);
//s.showarea();
Print(&s);
system("pause");
}