类多态

类多态

参考资料

虚函数表

多态(Polymorphism)按字面的意思就是“多种状态”。在面向对象语言中,接口的多种不同的实现方式即为多态。引用Charlie Calverts对多态的描述——多态性是允许你将父对象设置成为一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作(摘自“Delphi4 编程技术内幕”)。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。多态性在Object Pascal和C++中都是通过虚函数实现的。

override

覆盖,也可以说是重写,但和overwrite重写不一样,是翻译的问题,直接说英文。

  • 作为关键字,放在虚函数后面(形参列表后面,或者在const成员函数的const后面,或者是在引用成员函数的引用限定符&后面)
  • 覆盖要和虚函数的形参列表相同,不同的话就是一个独立的函数和基类没关系。但是一般不这么用,多数情况下是写错了才这么用的,这时编译器很难检测出来,为了方便调试,C++11 引入override关键字,当有这个关键字并且形参列表不同时,编译器会报错。

final(C++11)

  • 放在类名后面,则该类不能作为基类,避免继承。
  • 放在虚函数后面,则派生类不能override此函数(不能放在非虚函数后面)
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
#ifndef CLASS_TEST_H
#define CLASS_TEST_H

class A
{
public:
A():a(0),b(0) {};
~A() {};
void func1(int a);
void func1(double a);//重载
virtual void func2(int a);
virtual void func3(int a);
//virtual void func4(int a)=0;

private:
int a;
protected:
int b;
};

class A2
{
public:
A2() :a(0), b(0) {};
~A2() {};
//void func1(int a);
virtual void func1(int a)=0;//纯虚函数

private:
int a;
protected:
int b;

};
class B:public A
{
public:
void func1();//重写/隐藏。非虚函数
void func1(int a);//重写/隐藏
void func3(int a) override;//覆盖,编译器一般翻译成重写(但不是overwrite),override,也是虚函数(隐式的),也可以在前面加上virtual(显式)
void func3(int a, int b);//这是一个独立的函数,和基类没关系,
//不是覆盖(因为形参列表不同,如果加上overrid关键字编译器会报错),也不是重写(重写是基类的非虚)
;
};

class B2 :public A2
{
public:
B2():A2(){};
~B2();
void func1(int a);


};
#endif // !CLASS_TEST_H
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
#include "class_test.h"
#include <iostream>
using namespace std;
//class A
void A::func1(int a)
{
cout << "class A:func1(int)"<<a << endl;
}

void A::func1(double a)
{
cout << "class A:func1(double)" << a << endl;
}

void A::func2(int a)
{
cout << "class A virtual func2(int a)" << a << endl;
}

void A::func3(int a)
{
cout << "class A virtual func3(int a)" << a << endl;
}

//class A2
void A2::func1(int a)
{
cout << "class A2:func1(int a)" << a << endl;
}

//class B
void B::func1()
{
cout << "class B:func1" << endl;
}

void B::func1(int a)
{
cout << "class B:func1(int)" <<a <<endl;
}

void B::func3(int a)
{
cout << "class B:func3(int a)" << a<<endl;
}

void B::func3(int a, int b)
{
cout << "class B:func3(int a, int b)" << a << b << endl;
}



void B2::func1(int a)
{
cout << "class B2:func1(int a)" << a << endl;
}

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
#include"class_test.h"
int main()
{
A clsA;
clsA.func1(1);
clsA.func1(1.1);//重载
B claB;
claB.func1();
claB.func1(2);
claB.A::func1(2);//通过作用域改变调用函数
claB.func2(3);//B中没有func2
claB.func3(3);//B中有func3,覆盖
claB.A::func3(3);//通过作用域改变调用函数
claB.func3(3,4);//独立的函数
A *claAB=new B;
claAB = &claB;//子类指针可以赋给父类指针,反之不能
/*
导致错误输出的原因是,调用函数 func1() 被编译器设置为基类中的版本,
这就是所谓的静态多态,或静态链接 - 函数调用在程序执行前就准备好了。
有时候这也被称为早绑定,因为 func1() 函数在程序编译期间就已经设置好了。*/
claAB->func1(4);//静态多态,静态链接,早绑定
((B*)claAB)->func1(5);
((B*)claAB)->func2(5);//B中没有func2
claAB->func3(6);//动态多态,动态链接,后绑定

B* pclaB;
pclaB = &claB;
pclaB->func1(5);//重写,overwrite,隐藏了基类函数,注意和早绑定的区别

//A2 claA2;//错误,不能使用纯虚拟函数的对象
// A2* pclasA2 = new A2();//错误,不能使用纯虚拟函数的对象
A2* pclasA2 = new B2();//子类指针赋值给基类
pclasA2->func1(1);
//B2 claB2;
B2* pclaB2 = new B2();
pclaB2->func1(1);
return 0;
}

typeid

在c++中,typeid用于返回指针或引用所指对象的实际类型。
typeid是操作符,不是函数.
对非引用类型,typeid是在编译时期识别的,只有引用类型才会在运行时识别。

1
2
3
4
5
int a;
const type_info & info=typeid(a);
cout << info.name() << endl;//类型的名称
cout << info.raw_name() << endl;//名字编码(Name Mangling)算法产生的新名称
cout << info.hash_code() << endl;//返回当前类型对应的 hash 值
1
2
3
int
.H
3440116983