//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;
}