C++学习

面向对象核心概念与C++关键语法整理
一、面向对象三大特性(封装、继承、多态)

  1. 封装
    核心作用:保护类的内部数据,控制外部访问权限,提升代码安全性和可维护性。
    实现方式:通过访问修饰符(public/private/protected)限制类成员的可见性。
    操作三步走
  2. 私有化属性(private):将类的核心数据隐藏,禁止外部直接访问;
  3. 提供公有方法(public):通过get/set等成员函数封装对私有属性的访问逻辑;
  4. 添加访问控制语句:在公有方法中增加合法性校验(如数据范围、权限判断)。

访问修饰符详解

修饰符 访问范围
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;
}

  1. 继承
    核心作用:重用已有类(父类/基类)的代码和逻辑,减少冗余,实现代码复用。
    实现方式:通过父子类继承关系(class 子类 : 继承方式 父类),子类自动拥有父类的非私有成员。
    关键说明
  • 继承方式(public/protected/private)会改变父类成员在子类中的访问权限;
  • 子类可通过重写父类方法扩展逻辑,也可通过super(C++中直接用父类名)调用父类方法。
  1. 多态
    核心作用:扩展类的行为,实现“一个接口,多种实现”,提升代码灵活性和扩展性。
    实现方式:通过父类指针/引用指向子类实例,结合虚函数实现运行时动态绑定。

虚函数核心说明
虚函数是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++关键语法补充与强化

  1. 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. 指针相关语法
    (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;
}

  1. 宏定义
    define PI 3.1415926 // 宏定义常量,全局可用(预处理阶段替换,无类型检查)
    define MAX(a,b) ((a)>(b)?(a):(b)) // 宏定义函数,注意加括号避免优先级问题

三、面向对象开发流程(OOA→OOD→OOP)

  1. OOA(Object-Oriented Analysis,面向对象分析)
  • 核心目标:从现实世界抽象问题域,建立与实现无关的需求模型;
  • 核心工作:识别业务中的对象/类,梳理对象的属性、行为、关系(关联、继承、聚合等),明确需求边界。
  1. OOD(Object-Oriented Design,面向对象设计)
  • 核心目标:将OOA的分析结果细化为可落地的程序设计模型;
  • 核心工作
    1. 设计类的具体结构(属性、方法、访问控制);
    2. 规划类之间的关系(继承、组合、依赖);
    3. 应用封装、继承、多态三大特性优化设计;
    4. 设计接口、抽象类等可扩展结构。
  1. OOP(Object-Oriented Programming,面向对象编程)
  • 核心目标:使用C++/Java等面向对象语言,将OOD的设计模型编码实现;
  • 核心工作:编写类、实现继承与多态、调用对象方法,完成业务逻辑开发。
  • 本质:OOP = OOA(分析) + OOD(设计)的代码落地。

总结

  1. 面向对象三大特性中,封装靠访问修饰符保护数据,继承靠父子类复用代码,多态靠虚函数实现动态扩展;
  2. static关键字核心控制「存储期+作用域」:局部静态变量“一次初始化、全程存在”,类静态成员“属于类而非对象”,全局静态成员“文件内私有”;
  3. 指针是C++核心语法,需区分常量指针/指针常量、一级/二级指针、函数指针的不同用途,避免内存错误;
  4. 面向对象开发流程遵循“分析(OOA)→设计(OOD)→编程(OOP)”,从业务抽象到代码实现层层落地。
posted @ 2026-03-20 15:32  道长不姓王  阅读(14)  评论(0)    收藏  举报