c++学习文档

本文最后更新于 2025年7月19日 下午

  • 需要有c语言的前置知识

一,命名空间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
using namespace std; //使用std命名空间,可省略std::

//命名空间的声明和实现最好分开,在两个文件里,下面的放在.h文件里
namespace a {//命名空间a,只能在全局范围内定义,或者在类中定义,不能在函数内定义,或者嵌套定义
int aa = 10; //全局变量
//函数定义等等
namespace b { //命名空间b,嵌套在命名空间a中,a::b::
int bb = 20; //全局变量
//函数定义等等
}
}
cout << "a" << a::b::bb << endl;

//使用c语言的库
//一般在.h文件名前加c
//例如,include <cstdlib>

二,引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>

void test01() {//引用,相当于常量指针,引用必须初始化,且不能改变引用的对象
int a = 10;
//给a取别名
int& b = a; // int是a的类型,只需要在定义的时候加&,b只能在此引用一次,后面的均为赋值
//命名空间的使用
cout << "a" << a << endl;
cout << "b" << b << endl;
cout << "-----------------" << endl;
//操作b就相当于操作a
b = 100;
cout << "a" << a << endl;
cout << "b" << b << endl;
cout << "-----------------" << endl;
//一个变量可以有n个别名,它们的地址相同
}

int test02(int &x) { //函数返回值
return x; //返回值

三,内联函数

1
2
3
4
5
6
7
8
9
10
11
12
#define MAX(a,b) (a)>(b)?(a):(b)) //宏定义,返回两个数中的最大值,在代码中相当于文本替代,
//容易出现优先级混乱的问题,并且无安全性检查
//解决办法 --> 内联函数(inline)
inline int funcc(int a, int b) { //内联函数,编译器会将函数体替换到调用处,减少函数调用的开销
return a > b ? a : b; //返回两个数中的最大值
}//不能只声明,声明与实现一定要在一起
//内联函数只是一种建议,编译器可以选择是否内联,如果函数体过大,编译器可能不会内联
//内联函数只是优化后的宏定义,有一下任何情况,编译器不会内联:
//1,有循环语句
//2,过多的条件判断
//3,函数体过大
//4,对函数进行取址操作

四,函数重载

1
2
3
4
5
6
7
//c++的函数存在默认值,默认值规则和python类似,函数参数可以有默认值,默认值不能在声明和定义中同时设置

//函数重载,同一作用域内(命名空间),函数名相同,参数列表不同(参数个数、类型、顺序),返回值可以相同也可以不同,不通过返回值识别
//函数重载的例子
//int add(int a, int b); //函数声明
//int add(int a, int b, int c); //函数声明,参数个数不同
//int add(double a, double b); //函数声明,参数类型不同

五,类

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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#include <iostream>
#include <cstring>

class Animal {
//类的定义
public://访问权限修饰符,public表示公有成员,可以被外部访问,private,protected表示私有成员和保护成员,不能被外部访问(在继承中有区别)
//属性,不允许声明时设置值
int _age; //成员变量
int _height; //成员变量
int& p; //成员变量,引用类型,引用必须初始化,且不能改变引用的对象
char name[20]; //成员变量,数组类型

//------------------------------------------------------------------------------------------------
//需要在public下声明,构造函数名与类名相同,不能有返回值类型
//无参构造函数,如果没有定义任何构造函数,编译器会自动生成一个默认的无参构造函数
//若定义了有参构造函数,则必须定义无参构造函数,否则编译器不会生成默认的无参构造函数而报错
Animal():p(_age) {
//构造函数可以有参数,参数可以有默认值
cout << "Animal constructor called" << endl;
//可以对成员变量进行初始化
_age = 0; //初始化_age
_weight = 0; //初始化_weight
cout << "p引用的值:" << p << endl;
}
//有参构造函数1
Animal(int age, int height):_age(age), _height(height), p(age) {
cout << "Animal constructor called" << endl;
_age = age; //初始化_age
_height = height; //初始化_height
}
//有参构造函数2
Animal(int age):_age(age), p(age) {
cout << "Animal constructor called" << endl;
_age = age; //初始化_age
_height = 10; //初始化_height
}
//会根据参数的不同,调用不同的构造函数*********与函数重载类似

//初始化成员列表
//Animal(int age, int height):_age(age),_height(height),p(_age) {
//相当于
//_age = age;
//_height = height;
//}
//使用情况:
//1.当成员变量是const类型时,必须在初始化列表中初始化
//2.当成员变量是引用类型时,必须在初始化列表中初始化
//3.当成员变量是类类型时,必须在初始化列表中初始化

//类不会占用内存空间,只有对象实例化时才会占用内存空间

//析构函数,类的对象被销毁时调用,只能有一个,不能被重载
~Animal() { //析构函数,类名加~
cout << "Animal destructor called" << endl;
//析构函数可以有参数,但不能有返回值
//主要为了释放资源,比如动态分配的内存,文件句柄等
//free(p); //释放内存
//delete p; //释放内存
}
//------------------------------------------------------------------------------------------------

//方法
void eat(const int* voice) { //成员函数,const表示指针指向的内容不能被修改,指针本身可以修改
cout << _age << endl;
}//编译时自动加入this指针为参数,指向当前对象,保证对象中的函数与变量对应访问

int x, y, z;//通过this指针访问成员变量
int ABC(int x, int y, int z) { //成员函数,参数可以有默认值
this->x = x; //将参数a赋值给成员变量x
this->y = y; //将参数b赋值给成员变量y
this->z = z; //将参数c赋值给成员变量z
cout << "x: " << x << ", y: " << y << ", z: " << z << endl;
} //函数体

bool jump(int height); //成员函数声明,返回值为bool类型,参数为int类型,表示跳的高度

//静态成员变量(该类中的全局变量,同一类不同对象共享)
//静态成员变量在类中声明时使用static关键字,静态成员变量必须在类外定义
static int count; //静态成员变量,属于类本身,而不是某个对象,所有对象共享同一个静态成员变量。对于类的个数统计等场景非常有用

//静态成员函数
static void staticFunc() { //静态成员函数,属于类本身,而不是某个对象
cout << "This is a static function." << endl;
} //静态成员函数不能访问非静态成员变量和非静态成员函数

private: //私有成员,不能被外部访问
int _weight; //成员变量
};

//在类外实现成员函数(该函数必须提前声明)
bool Animal::jump(int height) { //类的成员函数实现,类名::函数名
if (height > 100) {
return true; //跳得高
}
return false; //跳得低
}

int main(){
//对象实例化
Animal cat; //创建Animal类的对象
cat._age = 10; //访问公有成员变量

//Animal cats[10]; //创建Animal类的多个对象

Animal* p;
p = &cat; //指针指向对象的地址
p->_age = 20; //通过指针访问对象的公有成员变量

memset(cat.name, 0, sizeof(cat.name)); //清空name数组,使用memset函数
strcpy_s(cat.name, "Jimes"); //字符串拷贝,将字符串"Tom"拷贝到cat.name中
cout << "Cat's name: " << cat.name << endl; //输出cat的name

//在堆上申请一个int类型的内存空间(4B),并将内容初始化为10
int* pp = new int(10);
//在堆上申请4个int类型的内存空间(16B)
int* arr = new int[4];
int* pp2 = new int[2] {10, 10};//无法批量初始化,必须指定大小
cout << "pp: " << pp2[1] << endl; //输出pp指向的内容

//在堆上申请4个Animal类型的内存空间
Animal* animalp1 = new Animal(5,15);
Animal* animalp2 = new Animal[4];

delete pp; //释放内存
delete[] pp2; //释放内存
delete[] arr; //释放内存
delete animalp1; //释放内存
delete[] animalp2; //释放内存
//注意:new和delete必须成对使用,new申请的内存必须用delete释放,new[]申请的内存必须用delete[]释放
//new和delete是C++的运算符,效率比malloc和free高,且new会调用构造函数,delete会调用析构函数
//malloc和free是C的函数,不会调用构造函数和析构函数,效率较低
//new自动计算内存大小,malloc需要手动指定内存大小
//new和delete直接带具体类型的指针,malloc和free需要强制转换类型
//new和delete可重载,且是安全的

//多个对象的构造和析构,类里面还有其它类
//先构造成员对象(多个成员对象按顺序),再构造当前对象;先析构当前对象,再析构成员对象(析构次序相反)

//class和struct的区别
//1.默认访问权限不同,class默认private,struct默认public
//2.继承方式不同,class默认private继承,struct默认public继承
//3.类的成员函数可以有默认参数,结构体的成员函数不能有默认参数
//4.类可以有虚函数,结构体不能有虚函数
//5.类可以有友元函数,结构体不能有友元函数
//6.类可以有静态成员变量,结构体不能有静态成员变量
//7.类可以有静态成员函数,结构体不能有静态成员函数
//8.类可以有虚基类,结构体不能有虚基类
//9.类可以有虚析构函数,结构体不能有虚析构函数
//10.类可以有虚函数表,结构体不能有虚函数表
//11.类可以有虚函数指针,结构体不能有虚函数指针
//12.类可以有虚函数表指针,结构体不能有虚函数表指针

//使用已构造的对象初始化另一个对象
//Animal dog;
//Animal dog2 = dog; //使用dog对象初始化dog2对象,此时为浅拷贝,dog2的成员变量与dog的成员变量(指针所指)指向同一块内存,且为默认拷贝构造函数
//解决办法:自定义拷贝构造函数,进行深拷贝
Animal(const Animal &t){ //t 引用的是右值对象
_age = t._age; //拷贝_age
_height = t._height; //拷贝_height
p = t.p; //拷贝p引用
strcpy_s(name, t.name); //拷贝name数组
//如果有指针成员变量,需要进行深拷贝,例如数组
}

//引用作为形参可以省去中间体的产生

//类的成员变量和成员函数存储在不同的内存区域(栈,代码段)

//定义静态成员变量
Animal::count = 0; //静态成员变量的定义,必须在类外定义

//调用静态成员函数,该函数只能访问静态成员变量和静态成员函数
Animal::staticFunc(); //调用静态成员函数

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
101
102
103
104
105
#include <string>

// 构造
string s1; //s1 = ""
string s2("Hello"); //s2 = "Hello"
string s3(4, 'k'); //s3 = "kkkk" (4个k)
string s3;
s3.assign(4, 'k');
string s4("12345", 1, 3); //s4 = "234" (从"12345"的第1个字符开始,取3个字符)
string s4;
s3.assign("12345", 1, 3);

//传入单个字符或数字,则错误
// string s5('a'); //错误,单个字符不能直接转换为string
// string s6(123); //错误,数字不能直接转换为string

// 赋值,字符串与字符严格区分
string s5,s6("hhhh");
s5 = s6; // s5 = "hhhh"
char s0 = 's';
s5 = s0; // s5 = "s",仍是字符串

// 拼接
s3 = s1 + s2; // 简单相加
// 使用append在末尾拼接,append会返回对象自身引用(修改作用在原变量上,不返回新变量)
string s7("123"),s8("abc");
s7.append(s8); // "123abc"
s7.append(s8,1,2); // "123abcbc"
s7.append(3,'k'); // "123abcbckkk"
s7.append("abcde",2,3); // "123abcbckkkcde"

// 比较字符串大小
// 比较规则:依次比较对应顺序的ASCLL码值,包括"/0"结束符,算0
bool ret;
ret = s2 > s3;
// 使用compare函数,比较部分字符串
string s1("hello"), s2("hello, world");
int n=s1.compare(s2);
n=s1.compare(1,2,s2,0,3);//比较s1的子串(1.2)和s2的子串(0,3)
n=s1.compare(0,2,s2);//比较s1的子串(0,2)和s2
n s1. compare("Hello");
n=s1.compare(1,2,"Hello");//比较s1的子串(1,2)和"Hello”
n=s1.compare(1,2,"Hello",1,2);//比较s1的子串(1,2)和"Hello”的子串(1,2)

// 求子串
string ss = s4.substr(1,3); // 第1个字符开始,取3个字符
ss = s4.substr(1); // 第1个字符开始,取完为止

// 查找子串或字符,find类,返回位置
find() //查找子串或字符的首次出现 str.find("abc")
rfind() //查找子串或字符的最后一次出现 str.rfind("abc")
find_first_of() //查找字符集合中的任意一个字符的首次出现 str.find_first_of("012")
find_last_of() //查找字符集合中的任意一个字符的最后一次出现 str.find_last_of("012")
find_first_not_of() //查找不在字符集合中的第一个字符 str.find_first_not_of(" \t")
find_last_not_of() //查找不在字符集合中的最后一个字符 str.find_last_not_of(" \t")

// 替换子串
string s1("Real Steel");
s1.replace(1, 3, "123456", 2, 4); // 用 "123456" 的子串(2,4) 替换 s1 的子串(1,3)
cout << s1 << endl; // 输出 R3456 Steel

string s2("Harry Potter");
s2.replace(2, 3, 5, '0'); // 用 5 个 '0' 替换子串(2,3)
cout << s2 << endl; // 输出 Ha00000 Potter

int n = s2.find("00000"); // 查找子串 "00000" 的位置. n=2
s2.replace(n, 5, "XXX"); // 将子串(n,5)替换为"XXX"
cout << s2 << endl; // 输出 HaXXX Potter

// 删除子串
string s1("Real Steel");
s1.erase(1, 3); // 删除从索引 1 开始的 3 个字符
cout << s1 << endl; // 输出 "R Steel"
s1.erase(5); // 删除从索引 5 开始到末尾的所有字符
cout << s1 << endl; // 输出 "R Ste"

// 插入字符串
string s1("Limitless"), s2("00");

s1.insert(2, "123"); // 在索引 2 处插入 "123"
cout << s1 << endl; // 输出 "Li123mitless"

s1.insert(3, s2); // 在索引 3 处插入 s2 ("00")
cout << s1 << endl; // 输出 "Li10023mitless"

s1.insert(3, 5, 'X'); // 在索引 3 处插入 5 个 'X'
cout << s1 << endl; // 输出 "Li1XXXXX0023mitless"

// 字符串分割
int main() {
char str[] = "Hello,world!This-is;a.test";
const char delimiters[] = ",!-;."; // 多个分隔符

// 第一次调用
char *token = strtok(str, delimiters);

// 后续调用
while (token != nullptr) {
std::cout << token << std::endl;
//从上一次分割的位置继续查找下一个标记,nullptr的含义
token = strtok(nullptr, delimiters);
}

return 0;
}

七,vector动态数组

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
#include <iostream>
#include <vector>

using namespace std;

int main() {
// 1. 创建一个空的vector(动态数组)
vector<int> dynamicArray;

// 2. 添加元素到数组末尾
dynamicArray.push_back(10); // 数组: [10]
dynamicArray.push_back(20); // 数组: [10, 20]
dynamicArray.push_back(30); // 数组: [10, 20, 30]

// 3. 访问元素
cout << "第一个元素: " << dynamicArray[0] << endl; // 输出: 10
cout << "第二个元素: " << dynamicArray.at(1) << endl; // 输出: 20

// 4. 修改元素
dynamicArray[1] = 25; // 数组变为: [10, 25, 30]

// 5. 获取数组大小
cout << "数组大小: " << dynamicArray.size() << endl; // 输出: 3

// 6. 遍历数组
cout << "数组元素: ";
for(int num : dynamicArray) {
cout << num << " ";
}
cout << endl;

// 7. 删除最后一个元素
dynamicArray.pop_back(); // 数组变为: [10, 25]

// 8. 插入元素到指定位置
dynamicArray.insert(dynamicArray.begin() + 1, 15); // 数组变为: [10, 15, 25]

// 9. 删除指定位置的元素
dynamicArray.erase(dynamicArray.begin()); // 数组变为: [15, 25]

// 10. 清空数组
dynamicArray.clear();
cout << "清空后数组大小: " << dynamicArray.size() << endl; // 输出: 0

return 0;
}

八,继承与派生

8.1 继承实例

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

// 基类
class Animal {
public:
void eat() {
cout << "动物可以吃" << endl;
}
void sleep() {
cout << "动物可以睡觉" << endl;
}
};

// 派生类
class Dog : public Animal {
public:
void bark() {
cout << "狗可以吠叫" << endl;
}
};

int main() {
Dog myDog;
myDog.eat(); // 继承自Animal
myDog.sleep(); // 继承自Animal
myDog.bark(); // Dog自己的方法

return 0;
}

8.2 继承方式

继承方式基类public成员基类protected成员基类private成员
publicpublicprotected不可访问
protectedprotectedprotected不可访问
privateprivateprivate不可访问
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// public继承
class PublicDerived : public Base {
// publicVar仍是public
// protectedVar仍是protected
// privateVar不可访问
};

// protected继承
class ProtectedDerived : protected Base {
// publicVar变为protected
// protectedVar仍是protected
// privateVar不可访问
};

// private继承
class PrivateDerived : private Base {
// publicVar变为private
// protectedVar变为private
// privateVar不可访问
};

8.3 构造函数与析构函数

1. 构造函数调用顺序

  • 基类构造函数
  • 成员对象构造函数(按声明顺序)
  • 派生类构造函数

2. 析构函数调用顺序

  • 与构造函数相反

8.4 多继承

1
2
3
4
5
6
7
8
9
10
class C : public A, public B {
public:
void showC() { cout << "C类方法" << endl; }
};

//派生类和基类的成员变量重名,默认访问的是派生类的成员变量
//访问基类成员:需要使用作用域解析运算符 ::
//----------------------派生 > 基类(就近原则)-----------------------------
//子类函数与父类函数名称相同,参数相同,且父类函数无virtual,父类被隐藏
//子类函数与父类函数名称相同,参数不同,父类被隐藏

8.5 虚继承与菱形继承

1
2
3
4
5
6
7
8
9
10
11
12
// 虚继承
class Mammal : virtual public Animal {};
class Bird : virtual public Animal {};

// 多重继承
class Platypus : public Mammal, public Bird {};

int main() {
Platypus p;
p.age = 5; // 没有二义性
return 0;
}
  1. 如果没有虚继承
    • Platypus会从Mammal和Bird各继承一个Animal基类
    • 这样Platypus内部会有两个age成员(分别来自Mammal路径和Bird路径)
    • 直接访问**p.age**会导致编译器不知道访问哪个age,产生二义性错误
  2. 使用虚继承后
    • 虚继承确保无论通过多少条继承路径,派生类中只包含一个共享的基类子对象
    • 所以Platypus中只有一个age成员
    • 访问**p.age**是明确的,不会产生二义性

8.6 静态成员

  • 静态成员被所有派生类共享
  • 静态成员属于类而非对象
  • 访问权限遵循继承规则

8.7 函数重载

1
2
3
4
5
6
7
8
9
10
// 重写
class Base {
public: // 有virtual才能被重写,否则隐藏无法重写
virtual void show() { cout << "基类show" << endl; }
};

class Derived : public Base {
public:
void show() override { cout << "派生类show" << endl; }
};

8.8 final关键字

1
2
3
4
5
6
7
8
9
//防止类被继承或虚函数被重写
class Base final { // 这个类不能被继承
// ...
};

class A {
public:
virtual void foo() final; // 不能被子类重写
};

8.9 多态

  • 面向对象编程的三大特性(封装、继承、多态)。

一、多态的基本概念

多态分为两种类型:

  1. 编译时多态(静态多态):通过函数重载和运算符重载实现
  2. 运行时多态(动态多态):通过虚函数和继承关系实现

二、编译时多态(静态多态)

1. 函数重载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>using namespace std;

class Print {
public:
void show(int i) {
cout << "整数: " << i << endl;
}
void show(double f) {
cout << "浮点数: " << f << endl;
}
void show(string s) {
cout << "字符串: " << s << endl;
}
};

int main() {
Print p;
p.show(5);
p.show(3.14);
p.show("Hello");
return 0;
}

2. 运算符重载(operator x)

  • 不能改变基础类型寓意。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>using namespace std;

class Complex {
private:
double real, imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
// 左操作数调用,右操作数当做实参
Complex operator + (Complex const &obj) {
return Complex(real + obj.real, imag + obj.imag);
}

void display() {
cout << real << " + " << imag << "i" << endl;
}
};

int main() {
Complex c1(3, 4), c2(1, 2);
Complex c3 = c1 + c2; // 对象相加
c3.display();// 输出: 4 + 6i
return 0;
}

三、*运行时多态(动态多态)

1. 虚函数实现多态

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

class Animal {
public:
virtual void speak() {// 虚函数
cout << "动物发出声音" << endl;
}
virtual ~Animal() {}// 虚析构函数};

class Dog : public Animal {
public:
void speak() override {// 重写虚函数
cout << "汪汪汪" << endl;
}
};

class Cat : public Animal {
public:
void speak() override {
cout << "喵喵喵" << endl;
}
};

void animalSpeak(Animal &animal) {
animal.speak();// 多态调用}

int main() {
Dog dog;
Cat cat;

animalSpeak(dog);// 输出: 汪汪汪animalSpeak(cat);// 输出: 喵喵喵

// 通过基类指针实现多态
Animal *animals[2];
animals[0] = new Dog();
animals[1] = new Cat();

for (int i = 0; i < 2; ++i) {
animals[i]->speak();
delete animals[i];
}

return 0;
}

2. 纯虚函数与抽象类

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

// 抽象类(包含纯虚函数)class Shape {
public:
virtual double area() const = 0;// 纯虚函数virtual ~Shape() {}
};

class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) {}
double area() const override {
return 3.14159 * radius * radius;
}
};

class Rectangle : public Shape {
private:
double width, height;
public:
Rectangle(double w, double h) : width(w), height(h) {}
double area() const override {
return width * height;
}
};

void printArea(const Shape &shape) {
cout << "面积: " << shape.area() << endl;
}

int main() {
Circle circle(5);
Rectangle rectangle(4, 6);

printArea(circle);// 输出: 面积: 78.5397printArea(rectangle);// 输出: 面积: 24

return 0;
}

四、多态的实现原理

多态是通过虚函数表(vtable)虚指针(vptr)实现的:

  1. 包含虚函数的类会有一个虚函数表
  2. 每个对象有一个指向虚函数表的指针(vptr)
  3. 调用虚函数时,通过vptr找到对应的虚函数表,再调用正确的函数

五、多态的优点

  1. 接口统一:不同对象可以使用相同的接口
  2. 可扩展性:容易添加新的派生类而不影响现有代码
  3. 代码复用:基类提供通用功能,派生类实现特定行为
  4. 灵活性:运行时决定调用哪个函数

六、使用多态的注意事项

  1. 基类析构函数应该声明为虚函数
  2. 不要滥用虚函数,会有一定的性能开销
  3. 纯虚函数使类成为抽象类,不能实例化
  4. 使用override关键字(C++11)可以明确表示重写虚函数

多态是面向对象编程中非常强大的特性,合理使用可以大大提高代码的灵活性和可维护性。


c++学习文档
https://jimes.cn/2025/07/19/c++学习文档/
作者
Jimes
发布于
2025年7月19日
许可协议