#C++ Day23 November 5 2025

//object – oriented 4 – 1 attribute & behavior

//面向对象 属性和行为

#include <iostream>

using namespace std;

//面向对象三大属性:封装、继承、多态

/*

封装指属性和行为的封装

封装的语法:

class 类名 {

访问权限:

属性(成员变量)

行为(成员函数)

};

*/

class Hero {

//访问权限 public private protected

public:

//属性

int m_Id; //m->member 成员 m代表member

int m_Hp; //血量

//行为

void addHp(int hp) {

m_Hp += hp;//加血

}

void subHp(int hp) {

m_Hp -= hp;//减血

}

};

int main() {

//通过类来生成对象的过程,叫实例化

Hero h;

//访问对象的属性

h.m_Id = 5;

h.m_Hp = 100;

h.addHp(100);

cout << “ID为”<<h.m_Id << “的英雄,血量是” << h.m_Hp << endl;

h.subHp(100);//最简单的类的封装

cout << “ID为” << h.m_Id << “的英雄,血量是” << h.m_Hp << endl;

return 0;

}

//object – oriented 4 – 2 access permission

//访问权限

#include <iostream>

using namespace std;

/*

访问权限:

公共权限 public 类内可以访问,类外也可以访问

保护权限 protected 类内可以访问,类外不可以访问  子类可以访问

私有权限 private     类内可以访问,类外不可以访问  子类不可以访问

B -> A  一个A类 一个B类 B类继承A类

A 父类、基类 属性:名字、房子、支付密码

B 子类、派生类   公有  保护  私有

*/

class People {

//公有权限

public:

int m_Id; //身份证号

//保护权限

protected:

int m_HouseId; //房子合同号

private:

int m_PayPass;//支付密码

public://在类里再写个函数

void work() {

//所有成员变量 类内均可以访问

m_Id = 1;

m_HouseId=2;

m_PayPass = 123;

}

private://在类里再写个函数

void work1() {

//所有成员变量 类内均可以访问

m_Id = 1;

m_HouseId = 2;

m_PayPass = 123;

}

};

//简单介绍继承

class Son : public People {//Son类继承了People类

void func() {

//在里面实现一个函数

m_Id = 1;

m_HouseId = 4; //保护成员,子类可以访问

//m_PayPass = 123; //私有成员,子类无法访问

}

};

int main() {

People p;//instantiate a class 实例化一个类

p.m_Id = 1;//公有成员 类外可以访问

//p.m_HouseId=5;//保护成员 类外不可以访问

//p.m_PayPass = 123;//私有成员 类外不可以访问

p.work();

//p.work1();//私有成员函数 类外不可以访问

return 0;

}

//Object – Oriented 4 – 3 class & struct

//class和struct区别

//C++里面它们两个只有访问权限的区别

#include <iostream>

using namespace std;

//struct && class

//struct 权限 默认是公共的

//class 权限 默认是私有的

class C {

int m_a;

};

struct S {

int m_a;

void func() {//C++的 struct 里面也可以定义成员函数  (C里面的struct 不可以定义成员函数)

m_a = 666;

}

};

int main() {

C c;//实例化对象

S s;

//c.m_a;//点不出来 私有的

s.m_a=4;//能点出来 公共的

cout << s.m_a << endl;

s.func();

cout << s.m_a << endl;

return 0;

}

AI:

在 C++ 中,#include <string> 的核心作用是让编译器识别并使用标准库中的 std::string 类。这背后涉及 C++ 的类型系统、标准库设计和编译机制,具体原因如下:

1. std::string 不是 C++ 的 “内置类型”

C++ 的 “内置类型”(如 int、char、double 等)是语言本身直接支持的基础类型,编译器天生认识它们,无需额外声明。

但 std::string 是标准库提供的 “类类型”(本质是对字符串的封装),它的定义、成员函数(如 size()、substr())、运算符重载(如 +、=)等逻辑并非由编译器内置,而是放在标准库的头文件中。

2. <string> 头文件包含 std::string 的完整声明

std::string 的 “设计蓝图”(类定义、成员函数声明等)被编写在 <string> 头文件中。当你在代码中使用 std::string 时(例如 std::string str = “hello”;),编译器需要知道:

  • 这个 std::string 是什么(类的结构)?
  • 它支持哪些操作(成员函数、运算符)?

如果不通过 #include <string> 引入这些信息,编译器会把 std::string 视为 “未定义的类型”,直接报错(例如 error: ‘string’ is not a member of ‘std’)。

3. 避免依赖 “间接包含” 的不可靠性

有时你可能发现,不显式包含 <string> 也能编译通过(例如包含了 <iostream> 等其他头文件时)。这是因为某些头文件(如 <iostream>)内部可能间接包含了 <string> 的部分内容(例如为了支持 cout << string 这样的操作)。

但这种 “间接包含” 是不可靠的

  • 标准并未规定其他头文件必须包含 <string>,不同编译器(如 GCC、Clang、MSVC)或标准库版本的实现可能不同;
  • 一旦依赖的间接包含被移除(例如编译器更新),代码会突然报错。

因此,显式包含 <string> 是规范且安全的做法

总结

#include <string> 的目的是向编译器提供 std::string 类的完整声明,让编译器能够识别并正确处理字符串对象的定义、初始化和操作。由于 std::string 是标准库类而非内置类型,必须通过包含对应头文件才能使用。

在Visual Studio中,打断点后有几种常用的下一步调试操作,核心快捷键如下:

1. 逐过程(F10):执行当前行代码并跳到下一行,遇到函数时不进入函数内部,直接执行完整个函数。

2. 逐语句(F11):和逐过程类似,但遇到函数调用时会进入函数体内,从函数第一行开始逐步调试。

3. 跳到下一个断点(F5):若设置了多个断点,按下后程序会连续执行,直到停在紧接着的下一个断点处。

4. 跳出函数(Shift+F11):若当前在函数内部调试,按下后会执行完函数剩余代码,直接跳回该函数的调用处并暂停。

在 SetSpeed 函数中,return 的作用是在参数不合法时提前退出函数,避免执行后续的赋值操作。

具体来说:当传入的 speed 小于 100 或大于 500 时,代码会先输出 “速度设置不合法”,然后通过 return 直接结束函数。这样一来,后续的 m_Speed = speed; 就不会被执行,从而阻止不合法的速度值被赋值给成员变量 m_Speed

如果没有这个 return,即使 speed 不合法,程序也会继续执行到 m_Speed = speed;,导致非法值被保存,违背了 “限制速度在 100-500 之间” 的设计逻辑。

简单说,这里的 return 是为了在参数无效时 “终止函数执行”,确保只有合法的参数才会生效

//Object – Oriented 4 – 4 attribute privatization

//面向对象 属性私有化

#include <iostream>

#include <string>

//STL字符内容

using namespace std;

//企业级开发时基本都会把一些属性设置为私有的 private 这样可以自由地定义读写权限

//接口、方法、函数 其实是同一个概念  都为了提供给外部调用

//好处:

//1.可以控制读写权限

//2.可以检测数据的有效性

class Hero{

public:

void SetName(string name) {

m_Name = name; //传一个name

}

string GetName() {

return m_Name;//不需要参数 直接返回成员变量就可以

}

int GetSkillCount() {

return m_SkillCount;

}

void SetSpeed(int speed) {

if (speed < 100 || speed>500) {

cout << “速度设置不合法” << endl;//检测速度是否合法

return;

}

m_Speed = speed; //传参传进去  拿不到值也可以在这按F9打个断点 开启Debug模式 然后程序跑到这一行中断 然后鼠标移上去标识符那就可看到666 按F10 往下执行一行 再去看m_Speed也变成666了

}

private:

string m_Name;//名字 可读可写  名字随便改随便取

int m_SkillCount=4;//技能数 只读 一个英雄技能数量固定 不能随便改

int m_Speed;//速度 只写 速度可以去修改 但是不需要获取它的速度值

};//如果直接开放公共的m_Speed 让外部去修改它 每次修改我都需要检测速度是否合法 但是我一旦抽象成函数后只需要检测一次就好了 这就是成员属性私有化的好处

//属性变成私有以后 可以通过一些方式来控制它的读写权限 可以用visual studio的监视来观察相应的变量

int main() {

Hero h;

/*

h.m_Name = “Vito”;

h.m_SkillCount = 4;

m.m_Speed = 100;

//都是私有成员 拿不到

*/

h.SetName(“Vito”);

cout << “英雄的名字叫:” << h.GetName() << endl;

cout << “英雄的技能数为:” << h.GetSkillCount() << endl; //输出乱码的话说明没有初始化

h.SetSpeed(666);

return 0;

}