跳到主要内容
C++ 类与对象(上):封装、实例化与 this 指针详解 | 极客日志
C++ 算法
C++ 类与对象(上):封装、实例化与 this 指针详解 C++ 类与对象基础涵盖类的定义格式、访问限定符区别、类域作用域规则、对象实例化过程及大小计算原理。重点解析 this 指针在成员函数中的作用机制,通过空指针调用测试说明其底层实现。最后对比 C 与 C++ 实现栈的差异,体现封装优势。
PhpPioneer 发布于 2026/3/22 更新于 2026/6/3 17 浏览C++ 类与对象(上):封装、实例化与 this 指针详解
引言
类是 C++ 面向对象编程的核心,实现了数据与方法的封装,其定义、访问限定与类域规则构成了基础框架。
实例化让抽象的类转化为实际内存中的对象,对象大小计算与成员函数存储特性,体现了 C++ 的内存设计逻辑。this 指针解决了成员函数区分对象的关键问题,而 C 与 C++ 实现 Stack 的对比,直观展现了封装带来的优势。
一、类的定义
1.1 基础:说明类的格式
class Stack {
};
class 为定义类的关键字,Stack 为类的名字,{}中为类的主体,最后面加上分号";"。类主体中的内容成为类的成员:类中的变量称为类的属性或者成员变量;类中的函数称为类的方法或者成员函数。
为了区分成员变量 ,一般会养成在成员变量加一个特殊的标识 的习惯,比如:在变量的前面或者后面加上_或者m—>_capacity等。但不是 C++ 强制的,只是为了方便操作,不同公司有着自己的书写规范。
C++ 中 struct 也可以定义类,因为 C++ 兼容 C 语言的 struct 用法,而且 C++ 将其升级成了类。一个明显的变化是 C++ 在 struct 可以定义函数,注意还是推荐 class 定义类 。
定义在类中的函数默认为 inline。(当然,最终还是取决于编译器)
class Stack {
void Init () {
}
void Push () {
}
int a;
int top;
int capacity;
};
int main {
Stack s1;
Stack s2;
;
}
()
return
0
在 C++,类与结构体高度相似 。其中明显的一个差异是:结构体名称不代表类型 ,只有当加上 struct 关键字后才是(或者 typedef 简化操作);而类可以直接使用名称 ,不需要加 class 关键字。
解释第 2 条:
对于命名规范,一般有一下几种:驼峰法
StackInit 自定义类型、函数 –>开头单词的首字母大写开头 + 后续每个单词的首字母都大写;
initCapacity 变量–>开头单词的首字母小写 + 后面的每个单词的首字母都大写。Google C++ 风格
stack_init 函数、init_capacity变量 --> 单词之间都用 _ 隔开。
1.2 关键:访问限定符 (class、struct)
C++一种实现封装 的方式,用类将对象的属性与方法结合在一起 ,使对象更完善,通过访问权限选择性的将其接口提供给外部用户使用。
访问权限 :public 修饰的成员在类外面可以直接访问;protected、private 修饰的成员只能在类内访问,对于二者具体的区别,等到继承部分就会体现,现在默认作用相同,但一般使用 private。
访问权限的作用域从该访问限定符出现位置开始到下一个访问限定符出现为止,如果后面没有访问限定符,作用域就到 }即类结束。
class 定义成员在没有被访问限定符修饰时默认为 private,但 struct 定义成员默认为 public。
类的成员变量通常会被限制为 private / protected 访问权限,而需要提供给外部使用的成员函数会设置为 public 访问权限。
class Stack {
public :
void Init (int capacity = 4 ) {
_a = nullptr ;
_top = 0 ;
_capacity = 0 ;
}
void Push (int x) {
}
private :
int * _a;
int _top;
int _capacity;
};
int main () {
Stack s1;
Stack s2;
s1. Init ();
s2. Push (1 );
return 0 ;
}
typedef struct A {
void func () {}
int a1;
int a2;
} A;
struct B {
public :
void Init () {
_a = nullptr ;
_top = 0 ;
_capacity = 0 ;
}
private :
int * _a;
int _top;
int _capacity;
};
int main () {
struct A a1;
A a2;
B b1;
return 0 ;
}
小贴士:
C++ 中类访问权限默认为私有。
C++ 中结构体访问权限默认为公有
对于这两者,一般还是用类。当然,如果一开始就希望类的权限是公开,比如定义链表节点继续用 struct。
1.3 类域(作用域)
类定义了一个新的作用域 ,类的所有成员都在类的作用域中,在类外定义成员 时(函数定义),就需要 :: 域操作符说明改成员属于哪个类域;
类域影响了编译查找的规则,当定义函数却不指明是哪个类域 ,编译器就将其视为普通的全局函数 ,导致编译时找不到成员变量的声明/定义 ,报错。指定了类域就知道函数是类的成员函数,在当前域找不到成员变量,就会去类域找。
#pragma once
#include <iostream>
class Stack {
public :
void Init (int capacity = 4 ) ;
void Push (int x) ;
private :
int * _a;
int _top;
int _capacity;
};
#include "stack.h"
void Stack::Init (int capacity) {
_a = nullptr ;
_top = 0 ;
_capacity = capacity;
}
void Stack::Push (int x) {
}
**–进行函数的声明定义分离:**定义类的成员函数需要指明类域。
(搜索变量顺序:现在局部局,后全局域以及类域)
#include "stack.h"
int main () {
Stack s1;
s1. Init ();
return 0 ;
}
二、实例化
2.1 解密:实例化的重要'身份'
用类这种类型在物理内存中创建对象的过程 ,称为类实例化出对象 ;
类是对象进行一种抽象描述,是一个模型一样的东西,限定了类有哪些成员变量 。这些成员变量只是声明,没有分配空间,只有用类实例化出对象时,才会分配空间 ;
一个类可以实例化出多个对象,实例化出的对象占用实际物理空间,存储类成员变量。比如:类实例化出对象就像用建筑设计图造房子,类就像设计图 ,规划了有多少个房间,房间大小功能等,但是并没有实体的建筑存在,也不能住人,用设计图修建出房子 ·,房子才能住人。同样类就像设计图,不能存储数据,实例化出的对象分配物理内存存储数据。
class Stack {
public :
void Init (int capacity = 4 ) {
_a = nullptr ;
_top = 0 ;
_capacity = capacity;
}
void Push (int x) {
}
private :
int * _a;
int _top;
int _capacity;
};
int main () {
Stack s1;
s1. Init ();
Stack s2;
s2. Push (2 );
return 0 ;
}
2.2 探究:对象的大小 类实例化出的对象,都有独立的数据空间,所以肯定包含成员变量 ,但是对于成员函数却不包含 。
首先函数被编译后是段指令,被存储在代码段(单独区域)中,这样对象也只能包含函数的指针,但是没有这个必要。
实例化出的对象调用的都是同一个函数 ,如果对象包含成员函数,空间就浪费了。在实际中,函数指针是一个地址,调用函数被编译成指令 [call 地址],编译器在编译链接只需要找到函数地址,不用再运行时找。(动态多态是在运行时找,这就需要存储函数地址,以后会学到)
知道了类包含着谁,就要开始计算对象的大小,这里,C++ 规定类实例化的对象符合内存对齐规则。
class A {
public :
void Init (int n = 4 ) {}
private :
char a;
int y;
};
int main () {
A s1;
s1. Init ();
A s2;
s2. Init (100 );
cout << sizeof (s1) << endl;
cout << sizeof (A) << endl;
return 0 ;
}
可以看到,根据对齐规则,内存大小为 8,没有包含成员函数。
class B {
void Init () {
}
};
class C {
};
int main () {
cout << sizeof (B) << '\n' ;
cout << sizeof (C) << endl;
return 0 ;
}
疑问?既然类不包含成员函数,为什么大小还是 1 呢?
这里就纯粹是为了占位标识对象存在,要不然谁知道对象存在过呢?!
三. this 指针
在上面 Stack 类中由成员函数 Init、Push,当类实例化两个对象时,二者调用同一个函数,是怎么区分的?这就是 C++ 隐含的 this 指针。
编译器编译后,类的成员函数默认会在形参的第一的位置增加一个当前类型的指针–this 指针 。比如:void Init(Stack* const this,...)。
类的成员函数访问成员变量,本质都是有 this 指针访问,比如:this->_capacity = capacity;。
C++ 规定不能在实参和形参的位置显示的写 this 指针 (编译时编译器会处理),但是可以在函数体内显示使用 this 指针。
#include <iostream>
using namespace std;
class Date {
public :
void Init (int year, int month, int day) {
this ->_year = year;
this ->_month = month;
_day = day;
}
void Print () {
cout << _year << "/" << _month << "/" << _day << '\n' ;
}
private :
int _year;
int _month;
int _day;
};
int main () {
Date d1;
Date d2;
d1. Init (2025 , 7 , 31 );
d2. Init (2025 , 7 , 9 );
d1. Print ();
d2. Print ();
return 0 ;
}
3.1 综合小测试
题目 1:下面的程序编译运行后的结果是(C),修改后的结果是(C)
#include <iostream>
using namespace std;
class A {
public :
void Print ()
{
cout << this << endl;
cout << "A::Print()" << endl;
}
private :
int _a;
};
int main () {
A* p = nullptr ;
p->Print ();
return 0 ;
}
在这里**可能很多人会选 B!**首先看到是对空指针指针 p 进行解引用(不会报错),但是编译器执行的就是注释中所示,而且对象不包含成员函数。
#include <iostream>
using namespace std;
class A {
public :
void Print () {
cout << this << endl;
cout << "A::Print()" << endl;
cout << _a << endl;
}
private :
int _a;
};
int main () {
A* p = nullptr ;
p->Print ();
return 0 ;
}
这里,对成员变量进行了访问,在前面已经说了编译器通过 this 指针访问成员函数的成员变量 ,所以发生空指针解引用!
题目 3:this 指针存在内存哪个区域的 (A)
A. 栈 B.堆 C.静态区 D.常量区 E.对象里面
this 是存在栈里面的,像形参一样,类似局部变量。但是 this 可能会被高频地访问,就会放在寄存器中。
四、C++ 和 C 语言实现 Stack 的对比 面向对象的三大特性:封装、继承、多态 ,通过对比 C++ 与 C 语言的代码风格进一步了解封装的概念。
C++ 中的数据和函数都放在类里面 ,通过访问限定符进行限制,无法通过对象直接修改数据 ,这就是封装的一种体现。
C++ 中有一些相对方便的语法,比如 Init 给的缺省参数会很方便,并且因为隐式的 this 指针,不再需要传递对象的地址,使用类型不用再 typedef。
虽然在 C++ 的入门阶段,感到实现 Stack 相较于 C 语言变化很多,但实际不大,等学到适配器实现 Stack 就会有新的体验 。
总结 类、实例化与 this 指针,共同构成 C++ 面向对象编程的核心基础。这些机制实现了数据与方法的封装,让代码更具规范性与可读性。通过与 C 语言的对比,C++ 面向对象的设计优势得以直观体现。掌握这些知识,也为后续学习继承、多态等高级特性,打下了坚实基础。
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
Gemini 图片去水印 基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online