C++ 多态
# 一、虚函数
- 类继承能够从已有的类派生出新的类,而派生类继承了原有类(称为基类)的特征,包括方法;
- C++ 中的虚函数是一种用于实现多态性的机制,它允许派生类重写基类的同名成员函数;
- 基类指针或引用调用派生类对象时,在运行时,根据其实际指向的对象,调用该类重写的成员函数;
- 其动态调用是通过虚函数表来实现的,实现于运行阶段;
- 一般通过
virtual
关键字来声明某个成员函数为虚函数; - 当基类中该函数没有实际意义时,可以通过
virtual
关键字声明后令其等于0,声明为纯虚函数,纯虚函数无法直接创建对象;
#include <iostream>
// 基类 Animal
class Animal {
public:
virtual void MakeSound() {
std::cout << "aaaaaaa" << std::endl;
}
};
// 派生类 Dog
class Dog : public Animal {
public:
void MakeSound() override {
std::cout << "wang wang wang ..." << std::endl;
}
};
// 派生类 Cat
class Cat : public Animal {
public:
void MakeSound() override {
std::cout << "miao miao miao ..." << std::endl;
}
};
int main() {
// 创建一个 Dog 对象,并通过基类指针调用虚函数
Animal* animal1 = new Dog();
animal1->MakeSound();
// 创建一个 Cat 对象,并通过基类指针调用虚函数
Animal* animal2 = new Cat();
animal2->MakeSound();
return 0;
}
/*
output:
wang wang wang ...
miao miao miao ...
*/
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
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
# 二、虚析构
- 当基类的析构函数前加上
virtual
关键字时,该析构函数为虚析构; - 基类指针指向派生类时:
- 在构造派生类对象时,会先执行基类构造函数,再执行子类构造函数;
- 在释放派生类对象时,会先执行子类析构函数,再执行基类析构函数;
- 连续多次继承时,从最顶级的父类依次向下执行构造函数,从最低级的子类依次向上执行析构函数;
- 如果基类析构函数不是虚析构函数,则释放派生类对象时,不会执行子类析构函数,可能会导致某些指针未释放;
点击查看
#include <iostream>
// 基类 Animal
class Animal
{
public:
Animal()
{
std::cout << "Animal construct" << std::endl;
}
explicit Animal(std::string name) : _name(name)
{
std::cout << "Animal construct, name: " << _name << std::endl;
}
virtual ~Animal()
{
std::cout << "Animal deconstruct" << std::endl;
}
private:
std::string _name;
};
// 派生类 Dog
class Dog : public Animal
{
public:
Dog()
{
std::cout << "Dog construct" << std::endl;
}
explicit Dog(std::string name) : Animal(name), _name(name)
{
std::cout << "Dog construct, name: " << _name << std::endl;
}
~Dog()
{
std::cout << "Dog deconstruct" << std::endl;
}
private:
std::string _name;
};
int main()
{
Animal *animal1 = new Dog();
delete animal1;
std::cout << "----------------------" << std::endl;
Animal *animal2 = new Dog("dog");
delete animal2;
return 0;
}
/*
Animal construct
Dog construct
Dog deconstruct
Animal deconstruct
----------------------
Animal construct, name: dog
Dog construct, name: dog
Dog deconstruct
Animal deconstruct
*/
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
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
# 三、多态
# 四、虚继承
# 五、虚表指针
- 编译器会为每个具有虚函数的类创建一个虚函数表,虚函数表中会依次存储每个虚函数的地址;
- 在类进行实例化时,会在每个实例对象的地址首位存储虚函数表的地址,即虚表指针;
- 虚表指针是编译器在具有虚函数的类的对象中插入的隐藏指针;
- 虚表指针的存在使得程序在运行时能够根据对象的实际类型动态地确定调用的是哪个虚函数;
- 以上述虚函数举例:
- animal1 实际指向的是
Dog
类的对象,那么会通过该对象的虚表指针找到其类的虚函数表,并调用其重载的虚函数;
- animal1 实际指向的是
# 六、其他
编辑 (opens new window)
上次更新: 2024/11/26, 21:55:31