注意:这篇文章上次更新于1836天前,文章内容可能已经过时。
This article was last updated1836 days ago, the content may be outdated.

本阶段主要针对C++面向对象编程技术做详细讲解,探讨C++中的核心和精髓。
This stage mainly provides a detailed explanation of C++ object-oriented programming techniques, exploring the core and essence of C++.
内存分区模型
C++程序在执行时,将内存大方向划分为4个区域
- 代码区:存放函数体的二进制代码,由操作系统进行管理的
- 全局区:存放全局变量和静态变量以及常量
- 栈区:由编译器自动分配释放, 存放函数的参数值,局部变量等
- 堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收
内存四区意义:
不同区域存放的数据,赋予不同的生命周期, 给我们更大的灵活编程
Memory Partition Model
When a C++ program runs, memory is broadly divided into 4 regions
- Code region: stores the binary code of function bodies, managed by the operating system
- Global region: stores global variables, static variables, and constants
- Stack region: automatically allocated and released by the compiler, storing function parameter values, local variables, etc.
- Heap region: allocated and released by the programmer; if the programmer does not release it, the operating system reclaims it when the program ends
The significance of the four memory regions:
Data stored in different regions is given different life cycles, providing us with greater programming flexibility
程序运行前
在程序编译后,生成了exe可执行程序,未执行该程序前分为两个区域
代码区:
存放 CPU 执行的机器指令
代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可
代码区是只读的,使其只读的原因是防止程序意外地修改了它的指令
全局区:
全局变量和静态变量存放在此.
全局区还包含了常量区, 字符串常量和其他常量也存放在此.
该区域的数据在程序结束后由操作系统释放.
示例:
Before the Program Runs
After the program is compiled, an exe executable is generated. Before the program is executed, it is divided into two regions
Code region:
Stores the machine instructions executed by the CPU
The code region is shared, so that frequently executed programs only need one copy of the code in memory
The code region is read-only, to prevent the program from accidentally modifying its instructions
Global region:
Global variables and static variables are stored here.
The global region also contains the constant region; string constants and other constants are stored here as well.
The data in this region is released by the operating system after the program ends.
Example:
1 | //全局变量 |
打印结果:

总结:
- C++中在程序运行前分为全局区和代码区
- 代码区特点是共享和只读
- 全局区中存放全局变量、静态变量、常量
- 常量区中存放 const修饰的全局常量 和 字符串常量
Print result:

Summary:
- In C++, before the program runs, it is divided into the global region and the code region
- The code region is characterized by sharing and being read-only
- The global region stores global variables, static variables, and constants
- The constant region stores const-modified global constants and string constants
After the Program Runs
Stack region:
Automatically allocated and released by the compiler, storing function parameter values, local variables, etc.
Note: do not return the address of a local variable; data opened on the stack is automatically released by the compiler
Example:
1 | int * func() |
堆区:
由程序员分配释放,若程序员不释放,程序结束时由操作系统回收
在C++中主要利用new在堆区开辟内存
示例:
Heap region:
Allocated and released by the programmer; if the programmer does not release it, the operating system reclaims it when the program ends
In C++, new is mainly used to open memory on the heap
Example:
1 | int* func() |
总结:
堆区数据由程序员管理开辟和释放
堆区数据利用new关键字进行开辟内存
Summary:
Heap data is opened and released by the programmer
Heap data is opened using the new keyword
new操作符
C++中利用new操作符在堆区开辟数据
堆区开辟的数据,由程序员手动开辟,手动释放,释放利用操作符 delete
语法:new 数据类型
利用new创建的数据,会返回该数据对应的类型的指针
示例1: 基本语法
The new Operator
In C++, the new operator is used to open data on the heap
Data opened on the heap is manually opened and manually released by the programmer, using the delete operator for release
Syntax: new data type
Data created with new returns a pointer of the corresponding type of that data
Example 1: basic syntax
1 | int* func() |
示例2:开辟数组
Example 2: opening an array
1 | //堆区开辟数组 |
References
Basic Use of References
Purpose: give a variable an alias
Syntax: data type &alias = original name
Example:
1 | int main() { |
Reference Precautions
- A reference must be initialized
- After initialization, a reference cannot be changed
Example:
1 | int main() { |
References as Function Parameters
Purpose: when passing parameters, the reference technique can be used to let formal parameters modify actual parameters
Advantage: it simplifies modifying actual parameters with pointers
Example:
1 | //1. 值传递 |
总结:通过引用参数产生的效果同按地址传递是一样的。引用的语法更清楚简单
Summary: the effect of passing by reference parameters is the same as passing by address. The reference syntax is clearer and simpler
References as Function Return Values
Purpose: a reference can exist as the return value of a function
Note: do not return references to local variables
Usage: function call used as an lvalue
Example:
1 | //返回局部变量引用 |
The Essence of References
Essence: the essence of a reference in C++ is internally implemented as a pointer constant.
Explanation example:
1 | //发现是引用,转换为 int* const ref = &a; |
结论:C++推荐用引用技术,因为语法方便,引用本质是指针常量,但是所有的指针操作编译器都帮我们做了
Conclusion: C++ recommends using the reference technique because the syntax is convenient. The essence of a reference is a pointer constant, but the compiler does all the pointer operations for us
Constant References
Purpose: constant references are mainly used to modify formal parameters to prevent accidental operations
In the function formal parameter list, you can add const to modify the formal parameters to prevent the formal parameters from changing the actual parameters
Example:
1 | //引用使用的场景,通常用来修饰形参 |
Function Enhancement
Default Parameters of Functions
In C++, the formal parameters in a function’s parameter list can have default values.
Syntax: return type function name (parameter = default value){}
Example:
1 | int func(int a, int b = 10, int c = 10) { |
函数占位参数
C++中函数的形参列表里可以有占位参数,用来做占位,调用函数时必须填补该位置
语法: 返回值类型 函数名 (数据类型){}
在现阶段函数的占位参数存在意义不大,但是后面的课程中会用到该技术
示例:
Placeholder Parameters of Functions
In C++, the formal parameter list of a function can contain placeholder parameters, used for holding a position; when calling the function, that position must be filled
Syntax: return type function name (data type){}
At this stage, placeholder parameters do not have much significance, but this technique will be used in later courses
Example:
1 | //函数占位参数 ,占位参数也可以有默认参数 |
函数重载
函数重载概述
作用: 函数名可以相同,提高复用性
函数重载满足条件:
- 同一个作用域下
- 函数名称相同
- 函数参数类型不同 或者 个数不同 或者 顺序不同
注意: 函数的返回值不可以作为函数重载的条件
示例:
Function Overloading
Overview of Function Overloading
Purpose: function names can be the same, improving reusability
Conditions for function overloading:
- Under the same scope
- Function names are the same
- Function parameters have different types or different numbers or different order
Note: the return value of a function cannot be used as a condition for overloading
Example:
1 | //函数重载需要函数都在同一个作用域下 |
Precautions for Function Overloading
- References as overloading conditions
- Function overloading encountering default parameters
Example:
1 | //函数重载注意事项 |
类和对象
C++面向对象的三大特性为:封装、继承、多态
C++认为万事万物都皆为对象,对象上有其属性和行为
例如:
人可以作为对象,属性有姓名、年龄、身高、体重…,行为有走、跑、跳、吃饭、唱歌…
车也可以作为对象,属性有轮胎、方向盘、车灯…,行为有载人、放音乐、放空调…
具有相同性质的对象,我们可以抽象称为类,人属于人类,车属于车类
Classes and Objects
The three major features of C++ object-oriented programming are: encapsulation, inheritance, and polymorphism
C++ considers that everything is an object, and objects have their attributes and behaviors
For example:
A person can be an object, with attributes such as name, age, height, weight…, and behaviors such as walking, running, jumping, eating, singing…
A car can also be an object, with attributes such as tires, steering wheel, lights…, and behaviors such as carrying people, playing music, using the air conditioner…
Objects with the same properties can be abstracted as classes; people belong to the human class, cars belong to the car class
封装
封装的意义
封装是C++面向对象三大特性之一
封装的意义:
- 将属性和行为作为一个整体,表现生活中的事物
- 将属性和行为加以权限控制
封装意义一:
在设计类的时候,属性和行为写在一起,表现事物
语法: class 类名{ 访问权限: 属性 / 行为 };
**示例1:**设计一个圆类,求圆的周长
示例代码:
Encapsulation
The Significance of Encapsulation
Encapsulation is one of the three major features of C++ object-oriented programming
The significance of encapsulation:
- Treat attributes and behaviors as a whole to express things in life
- Control access permissions for attributes and behaviors
Significance 1 of encapsulation:
When designing a class, write attributes and behaviors together to express things
Syntax: class class name{ access permission: attributes / behaviors };
Example 1: design a circle class to calculate the circumference of a circle
Example code:
1 | //圆周率 |
**示例2:**设计一个学生类,属性有姓名和学号,可以给姓名和学号赋值,可以显示学生的姓名和学号
示例2代码:
Example 2: design a student class with the attributes name and student ID. It can assign the name and student ID, and can display the student’s name and student ID
Example 2 code:
1 | //学生类 |
封装意义二:
类在设计时,可以把属性和行为放在不同的权限下,加以控制
访问权限有三种:
- public 公共权限
- protected 保护权限
- private 私有权限
示例:
Significance 2 of encapsulation:
When designing a class, attributes and behaviors can be placed under different permissions for control
There are three access permissions:
- public public permission
- protected protected permission
- private private permission
Example:
1 | //三种权限 |
The Difference Between struct and class
In C++, the only difference between struct and class is their default access permissions
Difference:
- The default permission of struct is public
- The default permission of class is private
1 | class C1 |
Setting Member Attributes to Private
Advantage 1: setting all member attributes to private allows you to control read/write permissions yourself
Advantage 2: for write permissions, we can validate the validity of the data
Example:
1 | class Person { |
练习案例1:设计立方体类
设计立方体类(Cube)
求出立方体的面积和体积
分别用全局函数和成员函数判断两个立方体是否相等。

Practice case 1: design a Cube class
Design a Cube class
Calculate the surface area and volume of the cube
Use a global function and a member function respectively to determine whether two cubes are equal.

练习案例2:点和圆的关系
设计一个圆形类(Circle),和一个点类(Point),计算点和圆的关系。

Practice case 2: the relationship between a point and a circle
Design a Circle class and a Point class, and calculate the relationship between a point and a circle.

对象的初始化和清理
- 生活中我们买的电子产品都基本会有出厂设置,在某一天我们不用时候也会删除一些自己信息数据保证安全
- C++中的面向对象来源于生活,每个对象也都会有初始设置以及 对象销毁前的清理数据的设置。
Initialization and Cleanup of Objects
- Electronic products we buy in life basically have factory settings, and when we no longer use them one day, we also delete some of our own information data to ensure security
- C++ object orientation originates from life; every object also has initial settings as well as cleanup settings before the object is destroyed.
构造函数和析构函数
对象的初始化和清理也是两个非常重要的安全问题
一个对象或者变量没有初始状态,对其使用后果是未知
同样的使用完一个对象或变量,没有及时清理,也会造成一定的安全问题
c++利用了构造函数和析构函数解决上述问题,这两个函数将会被编译器自动调用,完成对象初始化和清理工作。
对象的初始化和清理工作是编译器强制要我们做的事情,因此如果我们不提供构造和析构,编译器会提供
编译器提供的构造函数和析构函数是空实现。
- 构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。
- 析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。
构造函数语法:类名(){}
- 构造函数,没有返回值也不写void
- 函数名称与类名相同
- 构造函数可以有参数,因此可以发生重载
- 程序在调用对象时候会自动调用构造,无须手动调用,而且只会调用一次
析构函数语法: ~类名(){}
- 析构函数,没有返回值也不写void
- 函数名称与类名相同,在名称前加上符号 ~
- 析构函数不可以有参数,因此不可以发生重载
- 程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次
Constructors and Destructors
The initialization and cleanup of objects are also two very important safety issues
If an object or variable has no initial state, the consequences of using it are unknown
Similarly, if an object or variable is not cleaned up in time after use, it can also cause certain safety issues
c++ uses constructors and destructors to solve the above problems. These two functions will be automatically called by the compiler to complete object initialization and cleanup.
The initialization and cleanup of objects are things the compiler forces us to do, so if we do not provide a constructor and destructor, the compiler will provide them
The constructor and destructor provided by the compiler are empty implementations.
- Constructor: its main role is to assign values to the member attributes of the object when creating the object. The constructor is automatically called by the compiler and does not need to be called manually.
- Destructor: its main role is to be automatically called by the system before the object is destroyed to perform some cleanup work.
Constructor syntax: class name(){}
- The constructor has no return value and does not write void
- The function name is the same as the class name
- The constructor can have parameters, so overloading can occur
- When the program calls an object, the constructor is automatically called without manual invocation, and it is called only once
Destructor syntax: ~class name(){}
- The destructor has no return value and does not write void
- The function name is the same as the class name, with the symbol ~ added before the name
- The destructor cannot have parameters, so overloading cannot occur
- The destructor is automatically called before the object is destroyed, without manual invocation, and it is called only once
1 | class Person |
Classification and Calling of Constructors
Two classification methods:
By parameters: parameterized constructors and non-parameterized constructors
By type: ordinary constructors and copy constructors
Three calling methods:
Parenthesis method
Explicit method
Implicit conversion method
Example:
1 | //1、构造函数分类 |
When the Copy Constructor Is Called
In C++, the copy constructor is usually called in three situations
- Use an already created object to initialize a new object
- Pass values to function parameters by value
- Return a local object by value
Example:
1 | class Person { |
构造函数调用规则
默认情况下,c++编译器至少给一个类添加3个函数
1.默认构造函数(无参,函数体为空)
2.默认析构函数(无参,函数体为空)
3.默认拷贝构造函数,对属性进行值拷贝
构造函数调用规则如下:
-
如果用户定义有参构造函数,c++不在提供默认无参构造,但是会提供默认拷贝构造
-
如果用户定义拷贝构造函数,c++不会再提供其他构造函数
示例:
Constructor Calling Rules
By default, the C++ compiler adds at least 3 functions to a class
-
Default constructor (no parameters, empty function body)
-
Default destructor (no parameters, empty function body)
-
Default copy constructor, which performs value copy of attributes
The constructor calling rules are as follows:
-
If the user defines a parameterized constructor, C++ no longer provides a default non-parameterized constructor, but it will provide a default copy constructor
-
If the user defines a copy constructor, C++ will no longer provide other constructors
Example:
1 | class Person { |
Deep Copy and Shallow Copy
Deep and shallow copy is a classic interview question and also a common pitfall
Shallow copy: simple assignment copy operation
Deep copy: re-apply for space on the heap and perform the copy operation
Example:
1 | class Person { |
总结:如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题
Summary: if attributes are opened on the heap, you must provide your own copy constructor to prevent the problems caused by shallow copy
Initialization Lists
Purpose:
C++ provides initialization list syntax to initialize attributes
Syntax: constructor(): attribute1(value1), attribute2(value2)... {}
Example:
1 | class Person { |
Class Objects as Class Members
A member of a C++ class can be an object of another class; we call this member an object member
For example:
1 | class A {} |
B类中有对象A作为成员,A为对象成员
那么当创建B对象时,A与B的构造和析构的顺序是谁先谁后?
示例:
In class B, object A is a member, so A is an object member
Then when creating a B object, whose constructor and destructor come first between A and B?
Example:
1 | class Phone |
静态成员
静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员
静态成员分为:
- 静态成员变量
- 所有对象共享同一份数据
- 在编译阶段分配内存
- 类内声明,类外初始化
- 静态成员函数
- 所有对象共享同一个函数
- 静态成员函数只能访问静态成员变量
**示例1 :**静态成员变量
Static Members
Static members are member variables and member functions preceded by the keyword static
Static members are divided into:
- Static member variables
- All objects share the same data
- Memory is allocated at the compilation stage
- Declared inside the class, initialized outside the class
- Static member functions
- All objects share the same function
- Static member functions can only access static member variables
Example 1: static member variables
1 | class Person |
**示例2:**静态成员函数
Example 2: static member functions
1 | class Person |
C++ Object Model and the this Pointer
Member Variables and Member Functions Are Stored Separately
In C++, member variables and member functions inside a class are stored separately
Only non-static member variables belong to the object of the class
1 | class Person { |
this指针概念
通过4.3.1我们知道在C++中成员变量和成员函数是分开存储的
每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码
那么问题是:这一块代码是如何区分那个对象调用自己的呢?
c++通过提供特殊的对象指针,this指针,解决上述问题。this指针指向被调用的成员函数所属的对象
this指针是隐含每一个非静态成员函数内的一种指针
this指针不需要定义,直接使用即可
this指针的用途:
- 当形参和成员变量同名时,可用this指针来区分
- 在类的非静态成员函数中返回对象本身,可使用return *this
The Concept of the this Pointer
From 4.3.1, we know that in C++, member variables and member functions are stored separately
Each non-static member function only produces one function instance, which means multiple objects of the same type share one piece of code
Then the question is: how does this piece of code distinguish which object calls it?
c++ solves the above problem by providing a special object pointer, the this pointer. The this pointer points to the object to which the called member function belongs
The this pointer is a pointer implicitly present in every non-static member function
The this pointer does not need to be defined; it can be used directly
The purposes of the this pointer:
- When a formal parameter has the same name as a member variable, the this pointer can be used to distinguish them
- To return the object itself in a non-static member function, use return *this
1 | class Person |
Null Pointers Accessing Member Functions
In C++, a null pointer can also call member functions, but you must also pay attention to whether the this pointer is used
If the this pointer is used, you need to check it to ensure the robustness of the code
Example:
1 | //空指针访问成员函数 |
const修饰成员函数
常函数:
- 成员函数后加const后我们称为这个函数为常函数
- 常函数内不可以修改成员属性
- 成员属性声明时加关键字mutable后,在常函数中依然可以修改
常对象:
- 声明对象前加const称该对象为常对象
- 常对象只能调用常函数
示例:
const Modifying Member Functions
Constant functions:
- After adding const after a member function, we call this function a constant function
- Member attributes cannot be modified inside a constant function
- After adding the keyword mutable when declaring a member attribute, it can still be modified in a constant function
Constant objects:
- Adding const before declaring an object makes it a constant object
- Constant objects can only call constant functions
Example:
1 | class Person { |
友元
生活中你的家有客厅(Public),有你的卧室(Private)
客厅所有来的客人都可以进去,但是你的卧室是私有的,也就是说只有你能进去
但是呢,你也可以允许你的好闺蜜好基友进去。
在程序里,有些私有属性 也想让类外特殊的一些函数或者类进行访问,就需要用到友元的技术
友元的目的就是让一个函数或者类 访问另一个类中私有成员
友元的关键字为 friend
友元的三种实现
- 全局函数做友元
- 类做友元
- 成员函数做友元
Friend
In life, your home has a living room (Public) and your bedroom (Private)
All guests who come can enter the living room, but your bedroom is private, meaning only you can enter
However, you can also allow your close girlfriends or buddies to enter.
In programs, some private attributes also need to be accessed by special functions or classes outside the class, and that requires the friend technique
The purpose of a friend is to allow a function or class to access private members of another class
The keyword for a friend is friend
Three implementations of friend
- Global function as friend
- Class as friend
- Member function as friend
1 | class Building |
1 | class Building; |
1 |
|
Operator Overloading
Operator overloading concept: redefine existing operators to give them another function, to adapt to different data types
Plus Operator Overloading
作用:实现两个自定义数据类型相加的运算
Purpose: implement the addition operation of two custom data types
1 | class Person { |
总结1:对于内置的数据类型的表达式的的运算符是不可能改变的
总结2:不要滥用运算符重载
Summary 1: operators for expressions of built-in data types cannot be changed
Summary 2: do not abuse operator overloading
1 | class Person { |
总结:重载左移运算符配合友元可以实现输出自定义数据类型
Summary: overloading the left shift operator with friend can output custom data types
Increment Operator Overloading
Purpose: implement your own integer data by overloading the increment operator
1 |
|
总结: 前置递增返回引用,后置递增返回值
Summary: pre-increment returns a reference, post-increment returns a value
赋值运算符重载
c++编译器至少给一个类添加4个函数
- 默认构造函数(无参,函数体为空)
- 默认析构函数(无参,函数体为空)
- 默认拷贝构造函数,对属性进行值拷贝
- 赋值运算符 operator=, 对属性进行值拷贝
如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题
示例:
Assignment Operator Overloading
The C++ compiler adds at least 4 functions to a class
- Default constructor (no parameters, empty function body)
- Default destructor (no parameters, empty function body)
- Default copy constructor, which performs value copy of attributes
- Assignment operator operator=, which performs value copy of attributes
If an attribute in the class points to the heap, deep and shallow copy problems will also occur during assignment operations
Example:
1 | class Person |
Relational Operator Overloading
Purpose: overloading relational operators allows two custom-type objects to be compared
Example:
1 | class Person |
Function Call Operator Overloading
- The function call operator () can also be overloaded
- Because the way it is used after overloading is very similar to calling a function, it is called a functor
- There is no fixed way to write a functor; it is very flexible
Example:
1 | class MyPrint |
继承
继承是面向对象三大特性之一
有些类与类之间存在特殊的关系,例如下图中:

我们发现,定义这些类时,下级别的成员除了拥有上一级的共性,还有自己的特性。
这个时候我们就可以考虑利用继承的技术,减少重复代码
Inheritance
Inheritance is one of the three major features of object-oriented programming
Some classes have special relationships with each other, for example in the figure below:

We find that when defining these classes, the lower-level members not only have the commonalities of the upper level, but also have their own characteristics.
At this time, we can consider using the inheritance technique to reduce duplicate code
继承的基本语法
例如我们看到很多网站中,都有公共的头部,公共的底部,甚至公共的左侧列表,只有中心内容不同
接下来我们分别利用普通写法和继承的写法来实现网页中的内容,看一下继承存在的意义以及好处
普通实现:
Basic Syntax of Inheritance
For example, we see that many websites have a common header, a common footer, and even a common left-side list; only the central content differs
Next, we will use the ordinary approach and the inheritance approach to implement the content of a webpage, and see the significance and benefits of inheritance
Ordinary implementation:
1 | //Java页面 |
继承实现:
Inheritance implementation:
1 | //公共页面 |
总结:
继承的好处:可以减少重复的代码
class A : public B;
A 类称为子类 或 派生类
B 类称为父类 或 基类
派生类中的成员,包含两大部分:
一类是从基类继承过来的,一类是自己增加的成员。
从基类继承过过来的表现其共性,而新增的成员体现了其个性。
Summary:
The benefit of inheritance: it can reduce duplicate code
class A : public B;
A is called the subclass or derived class
B is called the parent class or base class
The members in a derived class consist of two major parts:
One part is inherited from the base class, and the other part is members added by itself.
The ones inherited from the base class express commonality, while the newly added members express its individuality.
Inheritance Methods
Inheritance syntax: class subclass : inheritance method parent class
There are three inheritance methods in total:
- Public inheritance
- Protected inheritance
- Private inheritance

Example:
1 | class Base1 |
The Object Model in Inheritance
Question: among the members inherited from the parent class, which ones belong to the subclass object?
Example:
1 | class Base |
利用工具查看:

打开工具窗口后,定位到当前CPP文件的盘符
然后输入: cl /d1 reportSingleClassLayout查看的类名 所属文件名
效果如下图:

结论: 父类中私有成员也是被子类继承下去了,只是由编译器给隐藏后访问不到
Use a tool to view:

After opening the tool window, locate the drive letter of the current CPP file
Then enter: cl /d1 reportSingleClassLayout the class name to view the name of the file it belongs to
The effect is shown in the figure below:

Conclusion: the private members in the parent class are also inherited by the subclass, but they are hidden by the compiler and cannot be accessed
Constructor and Destructor Order in Inheritance
After a subclass inherits from the parent class, creating a subclass object will also call the parent class constructor
Question: whose constructor and destructor comes first, the parent class or the subclass?
Example:
1 | class Base |
总结:继承中 先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反
Summary: in inheritance, the parent class constructor is called first, then the subclass constructor; the destructor order is the opposite of the constructor order
Handling Members with the Same Name in Inheritance
Question: when the subclass and the parent class have members with the same name, how can the subclass object access the same-named data in the subclass or parent class?
- To access the same-named member of the subclass, access it directly
- To access the same-named member of the parent class, you need to add the scope
Example:
1 | class Base { |
总结:
- 子类对象可以直接访问到子类中同名成员
- 子类对象加作用域可以访问到父类同名成员
- 当子类与父类拥有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域可以访问到父类中同名函数
Summary:
- A subclass object can directly access the same-named members in the subclass
- A subclass object can access the same-named members of the parent class by adding the scope
- When the subclass and the parent class have same-named member functions, the subclass hides the parent class’s same-named member functions; adding the scope can access the same-named functions in the parent class
Handling Same-Named Static Members in Inheritance
Question: how are same-named static members in inheritance accessed on subclass objects?
Static and non-static members with the same name are handled in the same way
- To access the same-named member of the subclass, access it directly
- To access the same-named member of the parent class, you need to add the scope
Example:
1 | class Base { |
总结:同名静态成员处理方式和非静态处理方式一样,只不过有两种访问的方式(通过对象 和 通过类名)
Summary: same-named static members are handled the same way as non-static members, except that there are two ways to access them (through objects and through class names)
多继承语法
C++允许一个类继承多个类
语法:class 子类 :继承方式 父类1 , 继承方式 父类2...
多继承可能会引发父类中有同名成员出现,需要加作用域区分
C++实际开发中不建议用多继承
示例:
Multiple Inheritance Syntax
C++ allows a class to inherit from multiple classes
Syntax: class subclass :inheritance method parent class 1 , inheritance method parent class 2...
Multiple inheritance may cause same-named members to appear in the parent classes, and the scope needs to be added to distinguish them
Multiple inheritance is not recommended in actual C++ development
Example:
1 | class Base1 { |
总结: 多继承中如果父类中出现了同名情况,子类使用时候要加作用域
Summary: in multiple inheritance, if same-named members appear in the parent classes, the subclass must add the scope when using them
菱形继承
菱形继承概念:
两个派生类继承同一个基类
又有某个类同时继承者两个派生类
这种继承被称为菱形继承,或者钻石继承
典型的菱形继承案例:

菱形继承问题:
-
羊继承了动物的数据,驼同样继承了动物的数据,当草泥马使用数据时,就会产生二义性。 -
草泥马继承自动物的数据继承了两份,其实我们应该清楚,这份数据我们只需要一份就可以。
示例:
Diamond Inheritance
Diamond inheritance concept:
Two derived classes inherit from the same base class
Some class inherits from both derived classes at the same time
This kind of inheritance is called diamond inheritance, or diamond-shaped inheritance
Typical diamond inheritance case:

Diamond inheritance problems:
-
Sheep inherited the data of Animal, and Camel also inherited the data of Animal. When Alpaca uses the data, ambiguity occurs. -
Alpaca inherited the data of Animal twice. Actually, we should be clear that we only need one copy of this data.
Example:
1 | class Animal |
总结:
- 菱形继承带来的主要问题是子类继承两份相同的数据,导致资源浪费以及毫无意义
- 利用虚继承可以解决菱形继承问题
Summary:
- The main problem brought by diamond inheritance is that the subclass inherits two copies of the same data, causing resource waste and being meaningless
- Virtual inheritance can be used to solve the diamond inheritance problem
多态
多态的基本概念
多态是C++面向对象三大特性之一
多态分为两类
- 静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名
- 动态多态: 派生类和虚函数实现运行时多态
静态多态和动态多态区别:
- 静态多态的函数地址早绑定 - 编译阶段确定函数地址
- 动态多态的函数地址晚绑定 - 运行阶段确定函数地址
下面通过案例进行讲解多态
Polymorphism
Basic Concepts of Polymorphism
Polymorphism is one of the three major features of C++ object-oriented programming
Polymorphism is divided into two types
- Static polymorphism: function overloading and operator overloading belong to static polymorphism, reusing function names
- Dynamic polymorphism: derived classes and virtual functions implement runtime polymorphism
The difference between static polymorphism and dynamic polymorphism:
- The function address of static polymorphism is bound early - the function address is determined at the compilation stage
- The function address of dynamic polymorphism is bound late - the function address is determined at the runtime stage
The following case explains polymorphism
1 | class Animal |
总结:
多态满足条件
- 有继承关系
- 子类重写父类中的虚函数
多态使用条件
- 父类指针或引用指向子类对象
重写:函数返回值类型 函数名 参数列表 完全一致称为重写
Summary:
Conditions for polymorphism
- There is an inheritance relationship
- The subclass overrides the virtual function of the parent class
Conditions for using polymorphism
- A parent class pointer or reference points to a subclass object
Override: when the function return value type, function name, and parameter list are exactly the same, it is called overriding
Polymorphism Case 1 - Calculator Class
Case description:
Use the ordinary approach and the polymorphism technique respectively to design a calculator class that performs operations on two operands
Advantages of polymorphism:
- Clear code organization structure
- Strong readability
- Beneficial for expansion and maintenance in both the early and late stages
Example:
1 | //普通实现 |
总结:C++开发提倡利用多态设计程序架构,因为多态优点很多
Summary: C++ development advocates using polymorphism to design program architecture because polymorphism has many advantages
纯虚函数和抽象类
在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容
因此可以将虚函数改为纯虚函数
纯虚函数语法:virtual 返回值类型 函数名 (参数列表)= 0 ;
当类中有了纯虚函数,这个类也称为抽象类
抽象类特点:
- 无法实例化对象
- 子类必须重写抽象类中的纯虚函数,否则也属于抽象类
示例:
Pure Virtual Functions and Abstract Classes
In polymorphism, the implementation of the virtual function in the parent class is usually meaningless; it mainly calls the content overridden by the subclass
Therefore, the virtual function can be changed to a pure virtual function
Pure virtual function syntax: virtual return type function name (parameter list) = 0 ;
When a class has a pure virtual function, this class is also called an abstract class
Abstract class characteristics:
- Objects cannot be instantiated
- The subclass must override the pure virtual functions in the abstract class, otherwise it is also an abstract class
Example:
1 | class Base |
Polymorphism Case 2 - Making Drinks
Case description:
The general process of making a drink is: boil water - brew - pour into the cup - add ingredients
Use the polymorphism technique to implement this case, providing an abstract base class for making drinks and subclasses for making coffee and tea

Example:
1 | //抽象制作饮品 |
虚析构和纯虚析构
多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码
解决方式:将父类中的析构函数改为虚析构或者纯虚析构
虚析构和纯虚析构共性:
- 可以解决父类指针释放子类对象
- 都需要有具体的函数实现
虚析构和纯虚析构区别:
- 如果是纯虚析构,该类属于抽象类,无法实例化对象
虚析构语法:
virtual ~类名(){}
纯虚析构语法:
virtual ~类名() = 0;
类名::~类名(){}
Virtual Destructors and Pure Virtual Destructors
When polymorphism is used, if a subclass has attributes opened on the heap, the parent class pointer cannot call the subclass’s destructor code when releasing
Solution: change the destructor of the parent class to a virtual destructor or pure virtual destructor
Common points of virtual destructors and pure virtual destructors:
- Can solve releasing subclass objects through parent class pointers
- Both need concrete function implementations
Differences between virtual destructors and pure virtual destructors:
- If it is a pure virtual destructor, the class is an abstract class and objects cannot be instantiated
Virtual destructor syntax:
virtual ~class name(){}
Pure virtual destructor syntax:
virtual ~class name() = 0;
class name::~class name(){}
示例:
1 | class Animal { |
总结:
1. 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象
2. 如果子类中没有堆区数据,可以不写为虚析构或纯虚析构
3. 拥有纯虚析构函数的类也属于抽象类
Summary:
1. Virtual destructors or pure virtual destructors are used to solve releasing subclass objects through parent class pointers
2. If there is no heap data in the subclass, it does not need to be written as a virtual destructor or pure virtual destructor
3. A class with a pure virtual destructor is also an abstract class
多态案例三-电脑组装
案例描述:
电脑主要组成部件为 CPU(用于计算),显卡(用于显示),内存条(用于存储)
将每个零件封装出抽象基类,并且提供不同的厂商生产不同的零件,例如Intel厂商和Lenovo厂商
创建电脑类提供让电脑工作的函数,并且调用每个零件工作的接口
测试时组装三台不同的电脑进行工作
示例:
Polymorphism Case 3 - Computer Assembly
Case description:
The main components of a computer are the CPU (for calculation), the video card (for display), and the memory module (for storage)
Encapsulate an abstract base class for each part, and provide different manufacturers to produce different parts, such as the Intel manufacturer and the Lenovo manufacturer
Create a computer class that provides a function to make the computer work, and calls the working interface of each part
During testing, assemble three different computers to work
Example:
1 |
|
文件操作
程序运行时产生的数据都属于临时数据,程序一旦运行结束都会被释放
通过文件可以将数据持久化
C++中对文件操作需要包含头文件 < fstream >
文件类型分为两种:
- 文本文件 - 文件以文本的ASCII码形式存储在计算机中
- 二进制文件 - 文件以文本的二进制形式存储在计算机中,用户一般不能直接读懂它们
操作文件的三大类:
- ofstream:写操作
- ifstream: 读操作
- fstream : 读写操作
File Operations
Data generated while the program runs is temporary; once the program finishes running, it is all released
Files can persist data
In C++, file operations require including the header file < fstream >
File types are divided into two kinds:
- Text file - the file is stored in the computer in the form of text ASCII codes
- Binary file - the file is stored in the computer in binary form, and users generally cannot read them directly
Three major classes for file operations:
- ofstream: write operations
- ifstream: read operations
- fstream : read and write operations
文本文件
写文件
写文件步骤如下:
-
包含头文件
#include <fstream>
-
创建流对象
ofstream ofs;
-
打开文件
ofs.open(“文件路径”,打开方式);
-
写数据
ofs << “写入的数据”;
-
关闭文件
ofs.close();
文件打开方式:
| 打开方式 | 解释 |
|---|---|
| ios::in | 为读文件而打开文件 |
| ios::out | 为写文件而打开文件 |
| ios::ate | 初始位置:文件尾 |
| ios::app | 追加方式写文件 |
| ios::trunc | 如果文件存在先删除,再创建 |
| ios::binary | 二进制方式 |
注意: 文件打开方式可以配合使用,利用|操作符
**例如:**用二进制方式写文件 ios::binary | ios:: out
示例:
Text Files
Writing Files
The steps for writing files are as follows:
-
Include the header file
#include <fstream>
-
Create a stream object
ofstream ofs;
-
Open the file
ofs.open(“file path”, opening method);
-
Write data
ofs << “data to write”;
-
Close the file
ofs.close();
File opening methods:
| Opening Method | Explanation |
|---|---|
| ios::in | Open the file for reading |
| ios::out | Open the file for writing |
| ios::ate | Initial position: end of file |
| ios::app | Append mode for writing |
| ios::trunc | If the file exists, delete it first, then create |
| ios::binary | Binary mode |
Note: file opening methods can be used together, using the | operator
For example: write a file in binary mode ios::binary | ios:: out
Example:
1 |
|
总结:
- 文件操作必须包含头文件 fstream
- 读文件可以利用 ofstream ,或者fstream类
- 打开文件时候需要指定操作文件的路径,以及打开方式
- 利用<<可以向文件中写数据
- 操作完毕,要关闭文件
Summary:
- File operations must include the header file fstream
- ofstream or fstream classes can be used to read files
- When opening a file, you need to specify the path of the file and the opening method
- << can be used to write data to a file
- After the operation, close the file
读文件
读文件与写文件步骤相似,但是读取方式相对于比较多
读文件步骤如下:
-
包含头文件
#include <fstream>
-
创建流对象
ifstream ifs;
-
打开文件并判断文件是否打开成功
ifs.open(“文件路径”,打开方式);
-
读数据
四种方式读取
-
关闭文件
ifs.close();
示例:
Reading Files
Reading files is similar to writing files, but there are relatively more reading methods
Steps for reading files:
-
Include the header file
#include <fstream>
-
Create a stream object
ifstream ifs;
-
Open the file and check whether it was opened successfully
ifs.open(“file path”, opening method);
-
Read data
Four ways to read
-
Close the file
ifs.close();
Example:
1 |
|
总结:
- 读文件可以利用 ifstream ,或者fstream类
- 利用is_open函数可以判断文件是否打开成功
- close 关闭文件
Summary:
- ifstream or fstream classes can be used to read files
- The is_open function can be used to determine whether the file was opened successfully
- close closes the file
二进制文件
以二进制的方式对文件进行读写操作
打开方式要指定为 ios::binary
写文件
二进制方式写文件主要利用流对象调用成员函数write
函数原型 :ostream& write(const char * buffer,int len);
参数解释:字符指针buffer指向内存中一段存储空间。len是读写的字节数
示例:
Binary Files
Perform read and write operations on files in binary mode
The opening method must be specified as ios::binary
Writing Files
Writing files in binary mode mainly uses the stream object to call the member function write
Function prototype: ostream& write(const char * buffer,int len);
Parameter explanation: the character pointer buffer points to a storage space in memory. len is the number of bytes to read or write
Example:
1 |
|
总结:
- 文件输出流对象 可以通过write函数,以二进制方式写数据
Summary:
- The file output stream object can write data in binary mode through the write function
读文件
二进制方式读文件主要利用流对象调用成员函数read
函数原型:istream& read(char *buffer,int len);
参数解释:字符指针buffer指向内存中一段存储空间。len是读写的字节数
示例:
Reading Files
Reading files in binary mode mainly uses the stream object to call the member function read
Function prototype: istream& read(char *buffer,int len);
Parameter explanation: the character pointer buffer points to a storage space in memory. len is the number of bytes to read or write
Example:
1 |
|
- 文件输入流对象 可以通过read函数,以二进制方式读数据
- The file input stream object can read data in binary mode through the read function


