news 2026/8/9 7:20:45

C++ 面向对象编程:类与对象、无名联合体、初始化列表

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++ 面向对象编程:类与对象、无名联合体、初始化列表

总前置:C 语言 面向过程 VS C++ 面向对象 核心对比(核心认知)

1. 编程思想本质区别

维度C 语言(面向过程 POP)C++(面向对象 OOP)
核心思路以函数 / 流程为中心,拆分步骤,关注「怎么做」以类 / 对象为中心,拆分实体,关注「谁来做、有什么属性」
数据与函数关系数据(结构体 struct)和函数完全分离,函数通过参数操作结构体数据,无绑定关系类封装属性(成员变量)+ 行为(成员函数),数据和操作绑定为整体
访问权限无权限控制,结构体成员全局可读写,极易误改数据私有 / 保护 / 公有三大访问控制,封装保护内部数据
代码复用函数复用、结构体复制;无继承机制,重复代码多继承、多态、复用类,大幅减少冗余代码
内存管理手动 malloc/free,无构造 / 析构,变量创建无自动初始化构造函数自动初始化、析构自动释放资源,支持 RAII 自动管理内存
复合数据类型仅基础结构体,不能包含函数,不支持联合体封装、常量成员类、结构体、联合体统一支持成员函数、权限、构造、继承

2. 最简示例对比:学生成绩存储

C 语言实现(分离式)
#include <stdio.h> // 只有数据,无操作函数 struct Student { char name[20]; int score; }; // 函数独立在外,需要传结构体指针操作数据 void showStu(struct Student* s) { printf("姓名:%s,分数:%d\n", s->name, s->score); } int main() { struct Student s = {"张三", 90}; showStu(&s); return 0; }

问题:score可以在任意地方随意修改,无法校验分数 0~100;数据和打印逻辑割裂。

C++ 类实现(封装一体)
#include <iostream> #include <string> using namespace std; class Student { private: string name; int score; // 私有数据,外部不能直接修改 public: // 构造函数自动初始化 Student(string n, int s):name(n),score(s){ if(score<0||score>100) score=0; // 数据校验 } // 成员函数绑定数据 void showStu() { cout << "姓名:" << name << ",分数:" << score << endl; } // 提供安全接口修改数据 void setScore(int s){ if(s>=0&&s<=100) score=s; } }; int main() { Student s("张三",90); s.showStu(); s.setScore(95); s.showStu(); // s.score = 200; 编译报错,私有成员禁止外部访问 return 0; }

优势:数据被保护,修改必须走校验接口,数据和行为绑定。


第一大部分:C++ 类与对象 完整核心知识点(基础必学)

1. 类(Class)与对象(Object)基础定义

(1)概念

  • :抽象模板,描述一类事物共同的属性(成员变量)行为(成员函数),相当于 C 语言结构体的超级增强版。
  • 对象:类的实例,根据类模板创建出具体实体,占用内存;一个类可以实例化无数对象。

(2)类完整语法结构

class 类名 { // 访问控制符:控制外部代码能否访问成员 public: // 公有:任意地方可访问 // 成员函数(对外接口) private: // 私有:仅本类内部成员函数可访问(默认权限) // 成员变量(核心数据,封装隐藏) protected: // 保护:本类+子类可访问,外部不可(继承专用) };

(3)C struct VS C++ class 关键差异(核心区分点)

  1. C 语言struct默认全部公有,只能存数据,不能写成员函数;
  2. C++struct:本质和 class 几乎一致,默认公有,支持成员函数、构造、继承;
  3. C++class默认私有,工程开发优先用 class 做封装。

示例:

// C++ struct 默认公有 struct StuStruct { int score; }; // C++ class 默认私有 class StuClass { int score; }; int main() { StuStruct s1; s1.score = 90; // 合法,默认public StuClass s2; // s2.score = 90; 编译报错,默认private return 0; }

2. 类的三大核心特性(OOP 核心精髓)

特性 1:封装(Encapsulation)

  1. 含义:将数据和操作数据的方法打包到类,隐藏内部私有细节,只对外暴露安全接口。
  2. 目的:
    • 保护数据,防止非法修改;
    • 简化调用,使用者不用关心内部实现;
  3. 实现手段:private私有成员 +public读写接口(get/set 函数)
  4. 对比 C 语言:C 无封装,结构体数据裸漏,无保护机制。

标准 get/set 模板:

class ExamInfo { private: int percent; public: // 获取值 int getPercent() { return percent; } // 安全设置值,附带校验 void setPercent(int p) { if(p >=0 && p <=100) percent = p; else cout << "分数非法!" << endl; } };

特性 2:继承(Inheritance)

  1. 含义:一个类(子类 / 派生类)复用另一个类(父类 / 基类)的所有公有、保护成员,扩展新功能。
  2. 对比 C 语言:C 语言无继承,代码复用只能复制粘贴,冗余严重。
  3. 基础语法:class 子类 : 继承方式 父类 {};
// 父类 class Person { protected: string name; public: void showName() { cout << name << endl; } }; // 子类Student继承Person class Student : public Person { private: int id; public: Student(string n,int i){ name = n; // 可直接访问父类protected成员 id = i; } };

特性 3:多态(Polymorphism)

  1. 含义:同一个接口,不同对象产生不同行为;依托虚函数实现。
  2. 对比 C 语言:C 语言无多态,只能用函数指针手动模拟,写法复杂。

3. 对象的创建、内存、访问方式

(1)两种创建对象方式

  1. 栈对象(自动释放,常用)
ExamInfo e("英语",'B');
  1. 堆对象(new 创建,手动 delete 释放)
ExamInfo* p = new ExamInfo("高数",true); delete p;

C 语言对比:C 只能malloc/free,无自动构造析构;C++ new 自动调用构造,delete 自动调用析构。

(2)成员访问运算符

  • .点运算符:栈对象访问e.show();
  • ->箭头运算符:对象指针访问p->show();C 语言结构体完全一致,但 C 没有成员函数。

4. 构造函数 & 析构函数(核心基础)

4.1 构造函数 Constructor

  1. 规则:函数名和类名完全相同,无返回值,对象创建时自动调用,仅执行一次;
  2. 作用:初始化对象成员,替代 C 语言手动赋值结构体;
  3. 分类:无参构造、有参构造、重载构造、拷贝构造;
  4. 对比 C 语言:C 无构造函数,结构体创建后必须手动赋值,容易忘记初始化产生垃圾值。

4.2 析构函数 Destructor

  1. 规则:~类名(),无参数无返回值,一个类只能 1 个析构;对象销毁时自动调用;
  2. 作用:释放堆内存、关闭文件、释放资源;
  3. 对比 C 语言:C 需要手动 free,忘记释放造成内存泄漏。

示例:

class Test { private: char* buf; public: // 构造 Test(){ buf = new char[100]; // 分配堆内存 } // 析构 ~Test(){ delete[] buf; // 自动释放,防止内存泄漏 } };

5. 常量对象、常成员函数(细节知识点)

  1. const 类名 对象:常量对象,只能调用常成员函数,不能修改任何成员;
  2. 常成员函数语法:void func() const {},函数内禁止修改成员变量;
  3. 对比 C 语言:C 无 const 对象区分,常量结构体依然可以通过指针篡改。

第二大部分:构造函数初始化列表 完整详解(含 C 对比、使用场景、细节坑点)

1. 完整语法回顾

类名(形参) : 成员1(值), 成员2(值), 联合体成员(值) { 函数体 }

2. 初始化列表 VS 函数体内赋值 VS C 语言结构体初始化

对比项C 语言结构体初始化C++ 构造函数初始化列表C++ 构造函数体内赋值
执行时机定义结构体时一次性赋值对象创建瞬间直接初始化成员成员先默认构造,再二次覆盖赋值
底层性能一次拷贝,无额外开销一次构造,性能最优两次构造,存在多余开销
const / 引用支持不支持完美支持直接编译报错
自定义类成员无法处理无参构造的类直接初始化,无报错编译失败
无名联合体C 语言不支持类内联合体直接初始化联合体成员赋值会覆盖内存,易乱码

3. 四种强制必须使用初始化列表场景(核心必记)

  1. 类内const常量成员;
  2. 引用类型成员;
  3. 包含自定义类对象,且该类无无参构造函数;
  4. 子类构造调用父类构造函数。

示例:const 成员只能用初始化列表

class Demo { private: const int a; // 常量,无法函数内赋值 public: // 正确:初始化列表赋值const Demo(int x):a(x){} // 错误写法:Demo(int x){ a = x; } 编译报错 };

4. 高频易错细节梳理

  1. 初始化顺序和书写顺序无关,严格按照类中成员声明从上到下初始化;
  2. 不能用后定义成员初始化前定义成员,产生随机垃圾值;
  3. 初始化列表不属于函数体代码,执行时机早于{}内部代码。

第三大部分:类内无名联合体 union 完整详解(ExamInfo 案例 + C 对比 + 代码细节 + 故障总结)

1. C 语言联合体 VS C++ 类内无名联合体 核心区别

  1. C 语言 union:独立数据类型,只能基础类型,必须定义变量才能访问,无法绑定逻辑标记;
  2. C++ 类内无名 union:嵌入类内部,成员直接作为类成员使用,配合类的枚举、构造函数自动管理;
  3. 共同特性:共用同一块内存,大小等于最大成员字节,同一时间仅一个数据有效。

2. 核心规则复盘

  1. 无名联合体语法:类内直接union { char grade; bool pass; int percent; };
  2. 访问简化:无需联合体对象,直接this->grade
  3. 配套机制:必须搭配枚举mode记录当前有效成员,否则读取乱码;
  4. 类型限制:联合体不能存放string、自定义类(带构造析构),只能内置基础类型。

3. 完整可编译案例代码(整合封装、重载构造、初始化列表)

#include <iostream> #include <string> using namespace std; class ExamInfo { private: string courseName; // 课程名 // 枚举标记:记录当前联合体哪个成员有效 enum { GRADE, PASS, PERCENTAGE } mode; // 类内无名联合体 union { char grade; // 等级制 A/B/C bool pass; // 通过/不通过 int percent; // 百分制 0-100 }; public: // 构造1:等级计分,初始化列表同步赋值mode+联合体 ExamInfo(string name, char g) : courseName(name), mode(GRADE), grade(g) {} // 构造2:通过标识计分 ExamInfo(string name, bool p) : courseName(name), mode(PASS), pass(p) {} // 构造3:百分制计分 ExamInfo(string name, int per) : courseName(name), mode(PERCENTAGE), percent(per) {} // 打印成绩函数 void show() { cout << courseName << ": "; switch (mode) { case GRADE: cout << grade << endl; break; case PASS: cout << (pass ? "PASS" : "FAIL") << endl; break; case PERCENTAGE: cout << percent << endl; break; default: cout << "数据无效,乱码!" << endl; } } }; int main() { ExamInfo e1("English", 'B'); ExamInfo e2("Calculus", true); ExamInfo e3("C++Programming", 85); e1.show(); e2.show(); e3.show(); return 0; }

输出结果:

plaintext

English: B Calculus: PASS C++Programming: 85

4. 高频故障、易错细节汇总(自学避坑核心)

  1. 数据乱码问题:只修改联合体成员,不更新 mode 枚举 → 读取乱码(最高频问题)
ExamInfo e("Math",90); e.percent = 59; // 修改联合体 // 忘记修改mode,show仍然读取百分制没问题;若再赋值grade不更新mode直接乱码
  1. 类型编译限制:联合体存储 string 等复杂类 → 编译报错,联合体仅支持无构造析构基础类型;
  2. 内存覆盖特性:同时给联合体多个成员赋值,后赋值直接覆盖前一个,数据丢失;
  3. C 语言原生缺陷:C 无法把 union 封装进结构体并绑定标记,只能手动维护状态,极易出错。

5. 内存占用计算示例

联合体成员:char (1B)、bool (1B)、int (4B) 最大类型 int 占 4 字节 → 联合体总内存 4 字节。 整个 ExamInfo 对象内存:string (系统固定大小) + 枚举 int (4B) + 联合体 (4B)。


第四大部分:核心知识点总汇总(自学复盘、查漏补缺)

一、基础概念核心要点

  • C++ 类默认访问权限:private;C++ struct 默认 public;C struct 无访问控制;
  • 初始化列表执行顺序:按成员声明顺序,和书写顺序无关;
  • 联合体内存大小等于内部最大基础类型;
  • const、引用成员必须使用初始化列表初始化;
  • 构造函数无返回值,析构函数唯一、无参;
  • 无名联合体成员直接属于外部类,无需对象前缀访问。

二、易混淆认知纠正

  • ❌ 错误认知:初始化列表书写顺序决定成员初始化顺序 → 正确:按类内成员声明顺序初始化
  • ❌ 错误认知:联合体可以同时保存多个有效数据 → 正确:内存覆盖,仅一个数据有效
  • ❌ 错误认知:C 语言结构体可以包含成员函数 → 正确:C 语言不支持,仅 C++ 支持
  • ✅ 正确认知:类内无名联合体不需要自定义类型名,直接定义使用
  • ✅ 正确认知:常量对象只能调用 const 修饰的常成员函数

三、代码编写高频注意事项

  • 构造函数体内禁止给 const、引用成员赋值,必须移到初始化列表;
  • 修改联合体成员时,必须同步更新 mode 枚举,避免数据乱码;
  • 类私有成员禁止外部直接访问,需封装 public get/set 读写接口;
  • 子类继承父类时,若父类无无参构造,必须在子类初始化列表调用父类有参构造;
  • 联合体中仅可定义基础内置类型,禁止定义 string、自定义类等复杂类型。

补充:C 语言 vs C++ 面向对象 核心总结

C 语言面向过程:数据和操作分离,无保护、无自动初始化、无复用机制; C++ 面向对象:类封装数据与行为,构造 / 析构自动管理资源,联合体、继承、多态扩展能力,严格权限控制,节省内存、代码易维护

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/9 7:15:44

冷热电联供系统多目标优化与MOPSO算法实践

1. 项目背景与核心价值冷热电联供型综合能源系统&#xff08;CCHP&#xff09;是当前能源领域的热门研究方向&#xff0c;它通过燃气轮机、燃气锅炉、电制冷机等设备的协同运行&#xff0c;实现能源的梯级利用。我在参与某工业园区能源系统改造项目时&#xff0c;深刻体会到这类…

作者头像 李华
网站建设 2026/8/9 7:14:46

智谱 Vibe Coding 上线前夜,我的测试密钥差点进了生产日志——验收红线的 7 次迭代

智谱 Vibe Coding 上线前夜,我的测试密钥差点进了生产日志--验收红线的 7 次迭代 智谱Vibe Coding生产密钥泄露事件全复盘:从危机到技术升级 事件始末:一场惊心动魄的36小时 灰度发布前36小时,部署在测试环境的智谱Vibe Coding突然开始往日志里狂吐JSON数据。当值班工程师检查…

作者头像 李华
网站建设 2026/8/9 7:11:58

Java面试中那些高频基础题,值得反复琢磨

“请说说你对String的理解。”面试官语气平淡&#xff0c;却像一枚探针&#xff0c;试图撬开你的知识体系。很多候选人心里一喜&#xff1a;这题我背过。于是流利地吐出“不可变、final、常量池”几个关键词。但接着面试官追问一句&#xff1a;“既然不可变&#xff0c;为什么S…

作者头像 李华
网站建设 2026/8/9 7:11:16

Kimi 工具调用翻车实录:模糊描述让准确率暴跌 60%,我用这套 Schema 模板救场

Kimi 工具调用翻车实录:模糊描述让准确率暴跌 60%,我用这套 Schema 模板救场 大模型工具调用优化实战:从混乱到精准的 Kimi 智能体改造记 灰度发布第二天,我的 Kimi 智能体突然开始胡言乱语。本该调用财务 API 核对报销金额,它却把用户地址簿里的经纬度坐标塞进了财务系统--这…

作者头像 李华
网站建设 2026/8/9 7:10:39

云端部署OpenClaw:Docker Compose一键部署AI助手框架

1. 项目概述&#xff1a;为什么你需要一个自己的OpenClaw最近在AI圈子里&#xff0c;OpenClaw这个名字出现的频率越来越高。你可能已经听说了&#xff0c;它是一个功能强大的AI助手框架&#xff0c;能够集成多种大语言模型&#xff0c;通过简单的指令完成复杂的自动化任务。但每…

作者头像 李华
网站建设 2026/8/9 7:08:55

彻底解决VC++运行库缺失问题:从原理到部署的完整指南

1. 项目概述&#xff1a;为什么Visual C运行库如此“烦人”&#xff1f;如果你在Windows上安装过游戏、专业软件&#xff0c;或者折腾过Python、Node.js、MySQL这类开发环境&#xff0c;大概率见过这个弹窗&#xff1a;“无法启动此程序&#xff0c;因为计算机中丢失VCRUNTIME1…

作者头像 李华