C++学习
面向对象核心概念与C++关键语法整理
一、面向对象三大特性(封装、继承、多态)
- 封装
核心作用:保护类的内部数据,控制外部访问权限,提升代码安全性和可维护性。
实现方式:通过访问修饰符(public/private/protected)限制类成员的可见性。
操作三步走: - 私有化属性(private):将类的核心数据隐藏,禁止外部直接访问;
- 提供公有方法(public):通过
get/set等成员函数封装对私有属性的访问逻辑; - 添加访问控制语句:在公有方法中增加合法性校验(如数据范围、权限判断)。
访问修饰符详解:
| 修饰符 | 访问范围 |
|---|---|
| public | 类外部可通过对象/类名直接访问(所有位置可见) |
| private | 仅类内部的成员函数/友元函数可访问(子类、外部均不可见) |
| protected | 类内部、子类/派生类可访问,外部不可见(继承场景专用) |
封装示例代码:
class Empty
{
private:
int x; // 私有化属性,外部无法直接访问
public:
// 构造函数:初始化对象,自动调用(优先执行)
Empty() {
x = 0;
std::cout << "create Empty" << std::endl;
}
// 析构函数:释放对象资源,自动调用(最后执行)
~Empty() {
std::cout << "delete Empty" << std::endl;
}
// 公有方法:封装对私有属性x的修改,添加控制逻辑
void setX(int val) {
// 访问控制:仅允许设置合法值
if (val >= 0) {
x = val;
std::cout << "setX: " << x << std::endl;
} else {
std::cout << "非法值,x保持原值:" << x << std::endl;
}
}
// 公有方法:封装对私有属性x的读取
int getX() {
return x;
}
};
int main() {
Empty e;
e.setX(10); // 输出:setX: 10(通过公有方法修改私有属性)
e.setX(-5); // 输出:非法值,x保持原值:10(访问控制生效)
// e.x = 20; // 编译报错:private属性无法直接访问
return 0;
}
- 继承
核心作用:重用已有类(父类/基类)的代码和逻辑,减少冗余,实现代码复用。
实现方式:通过父子类继承关系(class 子类 : 继承方式 父类),子类自动拥有父类的非私有成员。
关键说明:
- 继承方式(public/protected/private)会改变父类成员在子类中的访问权限;
- 子类可通过重写父类方法扩展逻辑,也可通过
super(C++中直接用父类名)调用父类方法。
- 多态
核心作用:扩展类的行为,实现“一个接口,多种实现”,提升代码灵活性和扩展性。
实现方式:通过父类指针/引用指向子类实例,结合虚函数实现运行时动态绑定。
虚函数核心说明
虚函数是C++实现多态的核心机制,在基类中用virtual关键字声明的成员函数:
- 允许子类重写(override)该函数,子类可自定义实现逻辑;
- 通过基类指针/引用调用时,程序会根据实际对象类型(而非指针/引用类型)执行对应版本的函数;
- 可理解为“可被子类定制的模板函数”:基类定义接口,子类实现具体逻辑。
多态示例代码:
using namespace std;
// 基类
class Animal {
public:
virtual void makeSound() { // 虚函数:定义接口
cout << "动物发出声音" << endl;
}
virtual ~Animal() {} // 虚析构函数:避免子类内存泄漏
};
// 子类重写虚函数
class Cat : public Animal {
public:
void makeSound() override { // override关键字校验重写合法性
cout << "喵喵喵" << endl;
}
};
int main() {
Animal* animal = new Cat(); // 父类指针指向子类实例
animal->makeSound(); // 输出:喵喵喵(动态绑定子类版本)
delete animal;
return 0;
}
二、C++关键语法补充与强化
- static(静态关键字)
核心作用:修改变量/函数的「存储期」和「作用域」,分为三大应用场景,补充细节如下:
(1)局部静态变量(函数内)
- 作用域:仅限定义它的函数/代码块内(与普通局部变量一致);
- 存储期:程序全程存在(静态存储区),普通局部变量存栈区,函数结束即销毁;
- 初始化:仅第一次执行到定义处时初始化,后续调用不再重复初始化;
- 线程安全:C++11后局部静态变量初始化时自动加锁,保证线程安全;
- 典型用途:统计函数调用次数、单例模式、缓存函数执行状态。
示例代码:
void countCall() {
static int count = 0; // 仅第一次调用初始化
count++;
std::cout << "函数调用次数:" << count << std::endl;
}
int main() {
countCall(); // 输出:1
countCall(); // 输出:2
countCall(); // 输出:3
return 0;
}
(2)全局静态变量/函数(文件级)
- 作用域:仅限定义它的编译单元(.cpp文件)内可见,其他文件无法访问;
- 存储期:程序全程存在(与普通全局变量一致);
- 链接属性:将默认的“外部链接”改为“内部链接”,避免多文件重定义冲突;
- C++替代方案:推荐用「命名空间+普通变量/函数」替代,语义更清晰。
示例代码:
// file1.cpp
static int global_static_var = 100; // 仅file1.cpp可见
static void static_func() { // 仅file1.cpp可见
std::cout << global_static_var << std::endl;
}
// file2.cpp
// extern int global_static_var; // 编译报错:无法访问file1的静态变量
// extern void static_func(); // 编译报错:无法访问file1的静态函数
(3)类的静态成员(变量/函数)
- 静态成员变量:
- 属于类本身,而非某个对象,所有对象共享同一份数据;
- 必须在类外初始化(
类型 类名::变量名 = 初始值),const static整型/枚举可在类内直接初始化; - 无this指针,不占用对象内存空间,存储在静态存储区。
- 静态成员函数:
- 属于类本身,无this指针,不能访问非静态成员(无法区分属于哪个对象);
- 不能被virtual修饰(虚函数依赖this指针);
- 访问方式:
类名::函数名()(推荐)或对象名.函数名()。
示例代码:
using namespace std;
class Student {
public:
static int total_count; // 静态变量:统计学生总数
string name; // 非静态变量:每个对象独有
Student(string n) : name(n) {
total_count++; // 创建对象时总数+1
}
// 静态函数:获取学生总数(仅能访问静态成员)
static int getTotalCount() {
return total_count;
// return name; // 编译报错:静态函数不能访问非静态成员
}
};
// 静态变量必须在类外初始化
int Student::total_count = 0;
int main() {
cout << "初始人数:" << Student::total_count << endl; // 输出:0
Student s1("Alice"), s2("Bob");
cout << "当前人数:" << Student::getTotalCount() << endl; // 输出:2
return 0;
}
static关键注意事项
- 静态变量生命周期与程序一致,若指向动态内存需手动释放,否则易导致内存泄漏;
- 局部静态变量在多线程场景下,C++11前可能存在初始化竞态问题;
- 类静态成员变量不属于对象,sizeof(类对象)不会包含其大小。
- 指针相关语法
(1)常量指针与指针常量
int a = 10, b = 20;
const int *p1 = &a; // 指向常量的指针:指针指向的值不可改,指针地址可改
// *p1 = 30; // 编译报错
p1 = &b; // 合法
int *const p2 = &a; // 常量指针:指针地址不可改,指向的值可改
*p2 = 30; // 合法
// p2 = &b; // 编译报错
(2)数组与指针
int a[5] = {1,2,3,4,5};
int *p = a; // 数组名等价于首元素地址,p指向a[0]
cout << *p << endl; // 输出:1
cout << *(p+2) << endl; // 输出:3(等价于a[2])
(3)二级指针
定义:指向指针的指针,存储指针变量的地址,语法:类型 **指针名。
用途:函数内修改一级指针指向、管理动态二维数组、遍历指针数组。
using namespace std;
void allocate(int **pp) {
*pp = new int[3]{10,20,30}; // 修改一级指针的指向
}
int main() {
int *p = nullptr;
allocate(&p); // 传入一级指针的地址(二级指针)
cout << p[0] << " " << p[1] << endl; // 输出:10 20
delete[] p;
return 0;
}
(4)函数指针
定义:指向函数的指针,存储函数的内存入口地址,语法:返回值类型 (*指针名)(参数列表)。
用途:回调函数、动态选择函数、函数表管理。
using namespace std;
void hi() {
cout << "Hello World!" << endl;
}
int main() {
void (func)(); // 定义无参、无返回值的函数指针
func = hi; // 指向hi函数
hi(); // 直接调用:输出Hello World!
(func)(); // 指针调用:输出Hello World!
return 0;
}
- 宏定义
define PI 3.1415926 // 宏定义常量,全局可用(预处理阶段替换,无类型检查)
define MAX(a,b) ((a)>(b)?(a):(b)) // 宏定义函数,注意加括号避免优先级问题
三、面向对象开发流程(OOA→OOD→OOP)
- OOA(Object-Oriented Analysis,面向对象分析)
- 核心目标:从现实世界抽象问题域,建立与实现无关的需求模型;
- 核心工作:识别业务中的对象/类,梳理对象的属性、行为、关系(关联、继承、聚合等),明确需求边界。
- OOD(Object-Oriented Design,面向对象设计)
- 核心目标:将OOA的分析结果细化为可落地的程序设计模型;
- 核心工作:
- 设计类的具体结构(属性、方法、访问控制);
- 规划类之间的关系(继承、组合、依赖);
- 应用封装、继承、多态三大特性优化设计;
- 设计接口、抽象类等可扩展结构。
- OOP(Object-Oriented Programming,面向对象编程)
- 核心目标:使用C++/Java等面向对象语言,将OOD的设计模型编码实现;
- 核心工作:编写类、实现继承与多态、调用对象方法,完成业务逻辑开发。
- 本质:OOP = OOA(分析) + OOD(设计)的代码落地。
总结
- 面向对象三大特性中,封装靠访问修饰符保护数据,继承靠父子类复用代码,多态靠虚函数实现动态扩展;
- static关键字核心控制「存储期+作用域」:局部静态变量“一次初始化、全程存在”,类静态成员“属于类而非对象”,全局静态成员“文件内私有”;
- 指针是C++核心语法,需区分常量指针/指针常量、一级/二级指针、函数指针的不同用途,避免内存错误;
- 面向对象开发流程遵循“分析(OOA)→设计(OOD)→编程(OOP)”,从业务抽象到代码实现层层落地。

浙公网安备 33010602011771号