标准C++(二)
一、名字空间
什么是名字空间
在C语言中定义的全局变量、函数、结构、联合、枚举、枚举值、宏都在全局作用域下,所以当项目比较庞大时,非常容易造成命名冲突(以模块名作前缀、后缀),所以C++中选择把全局作用域进行拆分成 子作用域进行管理,这些子作用域就是作名字空间。
如何设计名字空间
namespace 空间名 {// 子作用域在该作用域中定义全局变量、函数、结构、联合、枚举、枚举值...,不会与全局变量中的命名冲突 } // 此处没有分号
如何使用名字空间中的内容
方法1:
直接使用空间中的内容
空间名::标识符;
#include <iostream> int main(int argc,const char* argv[]) {std::cout << "我要使用std中的内容" << std::endl; return 0; }
方法2:
把空间中的部分内容导入到当作用域下,一旦导入之后就可以方便的直接使用
using 空间名::标识符;
#include <iostream> using std::cout; using std::endl; int main(int argc,const char* argv[]) {cout << "我要使用std中的内容" << endl; return 0; }
方法3:
把空间中的所有内容导入到当前作用域下
using namespace 空间名;
#include <iostream> using namespace std; int main(int argc,const char* argv[]) {string str = "string类也定义在std名字空间中";cout << str << endl;return 0; }
注意:C++标准库中提供的基础功能的类、对象都定义在std名字空间中,如:cout、cin、string。
空间合并与空间嵌套
1、编译器会把同名的名字空间的内容自动合并,同名的名字空间就是同一个作用域,如果同一个作用域 下有命名冲突编译就会报错。
#include <iostream> using namespace std; namespace ns {int num1 = 1234; } namespace ns {int num2 = 5678;int num1 = 6666; } int main(int argc,const char* argv[]) {using namespace ns;cout << num1 << " " << num2 << endl;return 0; }
2、名字空间中可以再定义名字空间
#include <iostream> using namespace std; namespace ns1 {namespace ns2 { namespace ns3 {int num = 123456789;}} } // 嵌套后的名字空间使用起来比较长,可以给内部名字空间取别名 namespace ns123=ns1::ns2::ns3; int main(int argc,const char* argv[]) {cout << ns1::ns2::ns3::num << endl;cout << ns123::num << endl;return 0; }
匿名名字空间
C++把默认的全局作用域当作一个没有名字的名字空间,也叫匿名名字空间,当全局的标识符被屏蔽,可以使用匿名空间的域限定符来指定全局作用域的标识符。
#include <iostream> using namespace std; int num = 1234; int main(int argc,const char* argv[]) {int num = 5678;cout << num << endl;cout << ::num << endl;return 0; }
注意:
工作时尽量不要使用 using namespace 空间名; 这种用法,这就像是把垃圾分类之后,又合并了,如果使用到标识符,一定要 空间名::标识符。
二、面向过程与面向对象
面向过程:
在编程时重点考虑如何解决问题,以及解决问题的具体步骤。
面向对象:
在编程时重点考虑的是"谁"能解决问题(类、结构),以及"它"解决问题时所需要属性(成员变量)和功能(成员函数)。
抽象:
把“解决问题者”当作思考或观察对象,把解决问题所需的具备的属性和功能罗列出来,这个步骤叫作抽象。
封装:
把抽象的结果(问题所需的具体的属性和功能),设置相应访问权限(public/private/protected),按照C++的语法设计成类、结构,该过程叫作封装类,简称封装。
使用封装好的类、结构,实例化出对象(定义结构变量、类变量),通过对象调用相关功能(成员函数)配合相关属性(成员变量)达到解决问题的目的。
继承:
1、在解决一个问题之前,先考虑现有的类是否能解决部分问题,如果有则继承该类,在此基础上进行扩展,以缩短解决问题的时间(代码复用)。
2、在解决一个复杂庞大的问题时,把问题拆分成若干个小问题,每个小问题实现一个类去解决,最后把这若干个类通过继承进行汇总,达到解决问题的目的,这个方式可以降低问题的规模在难度,也方便团队分工、协作。
多态:
语句的多种形态,同样的语句根据环境或参数的不同,有不同的功能,这就叫多态。
多态可以分为:
编译时多态,编译器在编译代码时根据语句的参数、环境不同,能翻译出具有不同功能的二进制指令,例如:调用重载的函数,cin、cout的自动类型识别,模板技术(后续讲解)。
运行时多态,语句只在程序运行时,才能确定执行那种功能,一般指的是类多态,后续再详细讲解。
#include <iostream> using namespace std; void func1(void) {cout << "我是func1函数" << endl; } void func2(void) {cout << "我是func2函数" << endl; } int main() {void (*fp)(void);int cmd;cin >> cmd;if(cmd % 2)fp = func1;elsefp = func2;fp(); }
三、类和对象
什么是类
把抽象结果(利用面向对象的思维模式,思考、观察出的结果),使用用C++的语法封装出一种类似结构的自定义数据类型(复合数据类型)。
如何设计类
struct 结构名 {成员函数; // 结构的成员默认访问权限是public成员变量; };class 类名 {成员变量; // 结构的成员默认访问权限是private成员函数; };注意:在C++中类的结构除了成员的默认访问权限不同,没有任何区别(大师兄说的)。
访问限制符
使用以下关键字修改结构、类的成员,管理它们的访问权限:
private: 私有的,被它修饰的成员,只能在类的成员函数内使用。 protected: 保护的,被它修饰的成员,只能在类、子类的成员函数内使用。 public: 公开的,被修饰的成员,可以在任何位置使用。
#include <iostream> using namespace std;struct Student {void in(void){ cout << "请输入学生的学号、姓名、年龄、成绩:"; cin >> id >> name >> age >> score;} void out(void){ // 学号:10010 姓名:hehe 年龄:18 成绩:100cout << "学号:" << id << " 姓名:" << name << " 年龄:" << age << " 成绩:" << score << endl;} private:int id; char name[20];short age;float score; };class Student {int id; char name[20];short age;float score; public:void in(void){ cout << "请输入学生的学号、姓名、年龄、成绩:"; cin >> id >> name >> age >> score;} void out(void){ // 学号:10010 姓名:hehe 年龄:18 成绩:100cout << "学号:" << id << " 姓名:" << name << " 年龄:" << age << " 成绩:" << score << endl;} };int main(int argc,const char* argv[]) {Student stu;stu.in();stu.out();return 0; }
什么是类对象
使用设计好的类(结构)这种数据类型,定义出的类变量在面向对象编程语言中被称为对象(结构变量),创建类对象的行为也被称为实例化对象。
#include <iostream> using namespace std;class Student {int id; char name[20];short age;float score; public:void in(void){ cout << "请输入学生的学号、姓名、年龄、成绩:"; cin >> id >> name >> age >> score;} void out(void){ // 学号:10010 姓名:hehe 年龄:18 成绩:100cout << "学号:" << id << " 姓名:" << name << " 年龄:" << age << " 成绩:" << score << endl;} };Student stu; // 在bss内存段上实例化对象 int main(int argc,const char* argv[]) {Student stu; // 在stack内存段实例化对象Student* stup = new Student; // 在heap内存段实例化对象 }
类的声明与实现分开
如果类的内容不多,一般会选择只定义一个头文件,以类名作为文件名。
#ifndef STUDENT_H #define STUDENT_Hclass 类名 {// 定义成员变量 public:// 定义成员函数 };#endif//STUDENT_H
如果类的内容比较多,会选择把类的声明与定义分开,头文件负责类的声明,源文件负责类的实现。
#ifndef STUDENT_H #define STUDENT_Hclass 类名 {// 定义成员变量 public:// 声明成员函数void 函数名(参数列表); };#endif//STUDENT_H
#include "student.h"void 类名::函数名(参数列表) {}
练习:实现C++版的通讯录。
四、构造函数与析构函数
构造函数
1、什么构造函数
类、结构、联合中的特殊成员函数,与类名、结构名、联合名同的成员函数,没有返回值。
class 类名 { public:类名(参数列表){} };
2、何时调用构造函数
当创建类对象时(实例化对象)会自动调用构造函数。
int main(int argc,const char* argv[]) {// 调用无参构造Student stu;Student* stup = new Student;// 调用有参构造Student stu1(10010,"hehe",'w',18,98);Student* stup1 = new Student(10011,"xixi",'m',20,95);// 调用有参构造,c11语法标准才支持,-std=c++11Student stu2 = {10010,"hehe",'w',18,98};return 0; }
3、在构造函数中应该做什么
构造函数负责创建使用对象的环境,一般构造函数中负责:
1、给成员变量初始化
2、给指针成员分配内存
3、从文件、网络、数据库加载数据
4、完成一些准备工作
4、实现构造函数要注意的问题
在创建类对象时,一定会调用构造函数,如果类中没有显式实现构造函数,编译器会自动生成一个无参的什么都不做的构造函数。
如果显式实现了有参构造函数,那么编译器就不会再生成无参构造。
注意:在使用new[] 创建n个对象时,无法保证给所有的类对象都单独提供参数,去调用有参构造,那么必然需要调用无参构造,此时如果没有显式实现无参构造,编译就会出错。
方法1:
class Student { public:Student() {} // 极简无参构造 };
方法2:
给有参构造函数的所有成员都设置默认形参,当需要调用无参构造时,会自动使用默认参数调用有参构造。
// 无参构造未必无参 class Student {... public:Student(int _id=0,const string& _name="",char _sex='w',short _age=0,float _score=0){id = _id;name = _name;sex = _sex;age = _age;score = _score;cout << "我是有参构造" << endl;} };
5、explicit关键字的作用
如果类中有单参的构造函数,那么它的参数类型数据就能隐藏提升为类对象,如果不使用该功能,可以在单参构造函数的前面加 explicit 关键字,参数类型数据就不能再隐藏提升为类对象。
总结:explicit关键字的作用就是禁止单参构造函数的类型提升功能。
#include <iostream> using namespace std;class Test {int num; public:[explicit] Test(int _num){ num = _num;} };void func(Test t) {cout << "我被调用了" << endl; }int main(int argc,const char* argv[]) {func(1234); }
析构函数:
1、什么析构函数
类、结构、联合中的特殊成员函数,在类名、结构名、联合的前面加~,就是析构函数,没有返回也没有参数。
struct Student {int id; string name;char sex;short age;float score; public:Student(void){cout << "我是无参构造函数" << endl;}Student(int _id,const string& _name,char _sex,short _age,float _score){ id = _id;name = _name;sex = _sex;age = _age;score = _score;cout << "我是有参构造" << endl;} ~Student(void){ cout << "我是析构函数" << endl;} };
2、在析构函数中应该做什么
析构函数负责对象销毁时的收尾工作,一般构造函数中负责:
1、释放指针成员指向的堆内存
2、往文件中、数据库保存数据
3、何时调用析构函数
1、当类对象离开它所在的作用域时,系统会自动销毁类对象,并自动调用析构函数。
#include <iostream> using namespace std;struct Student {int id;string name;char sex;short age;float score; public:Student(void){cout << "我是无参构造函数" << endl;}Student(int _id,const string& _name,char _sex,short _age,float _score){id = _id;name = _name;sex = _sex;age = _age;score = _score;cout << "我是有参构造" << endl;}~Student(void){cout << "我是析构函数" << endl;} };int main(int argc,const char* argv[]) {do{// 当创建类对象时,自动调用构造函数,当对象离开它的作用域时,会自动调用析构函数Student stu;}while(0);cout << "-----------" << endl; }
2、当使用delete或delete[] 释放堆内存上的类对象时,会自动调用析构函数(必须使用delete释放)。
#include <iostream> using namespace std;struct Student {int id;string name;char sex;short age;float score; public:Student(void){cout << "我是无参构造函数" << endl;}Student(int _id,const string& _name,char _sex,short _age,float _score){id = _id;name = _name;sex = _sex;age = _age;score = _score;cout << "我是有参构造" << endl;}~Student(void){cout << "我是析构函数" << endl;} };int main(int argc,const char* argv[]) {// 使用new 或 new[] 在堆内存上创建类对象时会自动调用构造函数Student* stup = new Student;Student* stus = new Student[10];// 类对象的个数,也是执行构造、析构函数的次数cout << *((int*)stus-1) << endl;// 使用delete 或 delete[] 释放堆内存上的类对象时会自动调用析构函数delete stup;delete[] stus;// 注意:使用new创建的就使用delete释放,使用new[]创建的就使用delete[]释放,不能混用return 0; }
4、析构函数要注意的问题
如果没有显式实现析构函数,那么编译器会自动生成一个什么都不做的析构函数。
如果构造函数中使用new、malloc分配的堆内存,就一定要显式实现析构函数,并在析构函数中释放堆内存,否则就会造成内存泄漏。
五、初始化列表与const成员
const成员
使用const修饰的类、结构、联合的成员变量,在类对象创建完成前一定要初始化。
不能在构造函数中初始化const成员,因为执行构造函数时,类对象已经创建完成,只有类对象创建完成才能调用成员函数,构造函数虽然特殊但也是成员函数。
在定义const成员时进行初始化,该语法只有在C11语法标准下才支持。
初始化列表
在构造函数小括号后面,主要用于给const成员初始化的一种特殊语法,也可以给普通成员初始化(可以解决参数名与成员变量名同名的问题)。
注意:如果有成员是类、结构、联合类型的,还可以在初始化列表中显式调用成员的构造函数,还可以调用父类的构造函数。
class 类名 {成员变量; public:构造函数(参数列表):成员变量(初始值),成员变量(初始值),...{} };
#include <iostream> using namespace std;class Test {// 可以使用,但只有C11标准才支持// const int num = 1234;const int num; public:Test(int num=0):num(num){ cout << "我是带初始化列表的构造函数" << endl;} void show(void){ cout << "const num = " << num << endl;} }; int main(int argc,const char* argv[]) {Test t(123456789);t.show();return 0; }
相关文章:

标准C++(二)
一、名字空间 什么是名字空间 在C语言中定义的全局变量、函数、结构、联合、枚举、枚举值、宏都在全局作用域下,所以当项目比较庞大时,非常容易造成命名冲突(以模块名作前缀、后缀),所以C中选择把全局作用域进行拆分…...

硬件工程师笔试面试——保险丝
目录 10、保险丝 10.1 基础 保险丝原理图 保险丝实物图 10.1.1 概念 10.1.2 保险丝的工作原理 10.1.3 保险丝的主要类型 10.1.4 保险丝的选择和使用注意事项 10.2 相关问题 10.2.1 保险丝的额定电流和额定电压是如何确定的? 10.2.2 保险丝的熔断速度对电路保护有何…...

本地安装Ollama+WebUI
本地安装OllamaWebUI B站教程地址:https://www.bilibili.com/video/BV1Kz421h7Jk/?spm_id_from333.337.search-card.all.click&vd_source42b07826977d09765ec11b9fa06715e5 一、下载Ollama https://ollama.com/download 支持mac、linux、windows 选择在ubu…...

请求响应-05.请求-日期参数JSON参数
一.日期参数 当浏览器发起的请求参数类型是日期参数时,我们通常使用LocalDateTime对象来接收,前面使用DateTimeFormat注解来完成日期的格式转换(日期时间格式有多种,需要哪种就设置为哪种:如yyyy-MM-dd HH:mm:ss&…...

CSS学习路线
CSS学习路线大全及面试常见题目可以归纳为以下几个部分: CSS学习路线大全 CSS基础 引入CSS的方式:外部样式表、内部样式表、内联样式。CSS选择器:包括ID选择器、类选择器、标签选择器、后代选择器、子选择器、相邻兄弟选择器、兄弟选择器、…...

Linux memcg lru lock提升锁性能
目录 内核关于per memcg lru lock的重要提交: 计算虚拟地址转换基本机制 问题背景 swap换入流程 时奎亮的per memcg lru lock分享视频 内核关于per memcg lru lock的重要提交: f9b1038ebccad354256cf84749cbc321b5347497 6168d0da2b479ce25a4647d…...

【spring】引入 Jackson 依赖 对java对象序列号和反序列化
Jackson Jackson 是一个非常流行的 Java 序列化/反序列化库,用于将 JSON 转换为 Java 对象,或者将 Java 对象转换为 JSON。要在你的 pom.xml 文件中引入 Jackson 依赖,你可以按照下面的步骤进行操作。引入 Jackson 依赖 通常,Jackson 核心库包含以下三个部分: jackson-dat…...

算法面经手撕系列(3)--手撕LayerNormlization
LayerNormlization 在许多的语言模型如Bert里,虽然都是说做的LayerNormlization,但计算均值和方差只会沿着channel维度做,并不是沿着seq_L和channel维度一起做,参考:BERT用的LayerNorm可能不是你认为的那个Layer Norm LayerNorm…...

出厂非澎湃OS手机解BL锁
脚本作者:酷安mlgmxyysd 脚本项目链接:https://github.com/MlgmXyysd/Xiaomi-HyperOS-BootLoader-Bypass/ 参考 B站作者:蓝空穹 https://www.bilibili.com/read/cv33210124/ 其他参考:云墨清风、水墨青竹、Magisk中文网 决定解BL…...

Go语言错误处理之道:优雅地应对程序中的问题
错误处理是任何编程语言中的关键部分,Go语言以其独特的错误处理机制而著称。对于初学者来说,理解Go语言中的错误处理对于编写健壮和可靠的程序至关重要。 为什么需要错误处理 在编程中,错误处理是必不可少的,因为程序可能会遇到…...

LIMS实验室管理系统的特点
LIMS实验室管理系统在实验室管理中发挥着不可或缺的作用。首要特点是其强大的自动化数据管理功能,该系统能够无缝集成实验室从样品接收到测试结果录入与存储的全过程,显著提升了数据的准确性和可靠性,减少了人为错误的可能性。 流程优化是LI…...

vue之 package.json和package-lock.json
一、package.json 定义了当前项目所需要引用的各个模块,可以手工修改配置,也可以删除后,使用npm init命令重新自动生成。 但是该文件只锁定大版本号,也就是版本号的第一位,所以你会发现两个文件中同一个包的版本号不一…...

android 老项目中用到的jar包不存在,通过离线的方法加载
1、之前的项目用的jar包,已经不在远程仓库中,只能手工去下载,并且安装。 // implementation com.github.nostra13:Android-Universal-Image-Loader // implementation com.github.lecho:hellocharts-android:v1.5.8 这…...

每天五分钟玩转深度学习框架PyTorch:梯度下降之学习率衰减
本文重点 我们前面学习了优化器optim,然后学习了为神经网络不同层设置不同的学习率,本节课程我们讲解学习率衰减的方法,也就是说如何在训练过程中动态的修改学习率,本文介绍两种方法。本文是学习第6步(优化器) 为什么要进行学习率衰减 对于一阶梯度进行优化的方法而言,…...

智能家居配上高颜值UI,瞬间感觉消费不起了呢
高颜值的UI设计可以给智能家居产品带来奢华和高端的感觉,为大家分享一波搞颜值界面。 高颜值的智能家居界面设计可以带来以下优势和好处: 用户体验提升: 高颜值的界面设计可以提升用户的视觉享受和满意度。精美的界面设计可以给用户带来愉…...

Winform登录实现及工具栏切换
1、登录实现 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms;namespace LoginApp {public par…...

Git bash使用
将本地文件推送到github上 先在所在文件夹进行初始化 git init绑定你的远程仓库 git remote add origin URL 随即 git add 指定文件 ——将工作区域中的文件添加到缓冲区 git commit -m【提交附带的信息】 git push origin master 推送到远程仓库 推送的时候可能会出现一些情…...

Java入门程序-HelloWorld
Java程序开发的三个步骤 1.编写代码得到 .java 源代码文件 2.使用javac编译得到 .class 字节码文件 3.使用java运行 注意事项 建议代码文件名全英文,首字母大写,满足驼峰命名法,源代码文件的后缀必须是.java 开发HelloWorld程序 &…...

计算机人工智能前沿进展-大语言模型方向-2024-09-12
计算机人工智能前沿进展-大语言模型方向-2024-09-12 1. PharmaBench: Enhancing ADMET benchmarks with large language models Z Niu, X Xiao, W Wu, Q Cai, Y Jiang, W Jin, M Wang… - Scientific Data, 2024 大语言模型在药物发现中的应用:PharmaBench 文章由…...

Android MediaPlayer + GLSurfaceView 播放视频
Android使用OpenGL 播放视频 概述TextureView的优缺点OpenGL的优缺点 实现复杂图形效果的场景参考 概述 在Android开发中,使用OpenGL ES来渲染视频是一种常见的需求,尤其是在需要实现自定义的视频播放界面或者视频特效时。结合MediaPlayer,我…...

gitee远程仓库OPEN GIT BASH HERE从错误中学习
推荐一个ai软件(搜索器搜索kimi),是一个ai,有什么错误跟着一步步解决就可以了 当你创建一个仓库 会出现这些 打开这个窗口跟着敲就行了 到这里为止我还没出现错误,后面我把remote add添加远程仓库的地址输错地址了 所…...

如何查看当前系统中所有具有sudo权限的用户?
要查看当前系统中所有具有 sudo 权限的用户,你可以使用以下方法: 方法一:查看 /etc/sudoers 文件 你可以直接查看 /etc/sudoers 文件,找到具有 sudo 权限的用户和用户组。请使用 visudo 命令来编辑和查看该文件,因为…...

在线制作PPT组织架构图!这个AI工具简单又好用!
ppt组织架构图如何制作,用哪个软件好? 在现代商业世界中,组织架构图是展示公司结构和层级关系的重要工具,譬如内部沟通或者对外展示等场合下,一个精美且清晰的组织架构图都能有效传达信息,提升企业形象。 …...

Mysql 视图存储过程触发器
初识: 在 MySQL 中,视图(View)、存储过程(Stored Procedure)和触发器(Trigger)是用于管理和操作数据库的高级功能。它们各自有不同的用途和优势。 2. 视图 (View) 视图是一个虚拟表,它是从一个或多个表中获取数据的结果。视图并不存储数据本…...

【天池比赛】【零基础入门金融风控 Task2赛题理解】实战进行中……20240915更新至2.3.4.3 查看训练集测试集中特征属性只有一值的特征
2.3 代码示例 2.3.1 导入数据分析及可视化过程需要的库 import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns import datetime import warnings warnings.filterwarnings(ignore) 2.3.2 读取文件 #读取数据时相对路径载入报错时…...

配置Windows内核开发环境
前言 以前在书上看到,说现在的安全软件已经将对抗转移到内核层了,深以为然。 因为像360安全卫士,腾讯电脑管家这样的安全软件,仅通过用户层api很难做到更高级的防御和控制。 早些年我想获取电脑硬盘的详细使用信息,…...

nanoGPT用红楼梦数据从头训练babyGPT-12.32M实现任意问答
1. 引入 大神karpathy从openai离职后,创办了AI教育公司Eureka Labs(参考1),同时也创办了知名的nanoGPT项目。 目前,使用nanoGPT(参考2),你可以在几分钟内训练出一个babyGPT…...

PDF转图片的思路思考
记录时间:2022年9月1日 PDF转图片库的使用和扩展 python有几个开源的免费的处理Pdf的库,甚至有的已经有很完善的功能了。我发挥一下自己的所学,看看能不能把它变为可用的一程序。 首先是了解PDF处理库PyMupdf,这个库得到路径之后普就可以对…...

lnmp - 登录技术方案设计与实现
概述 登录功能是对于每个动态系统来说都是非常基础的功能,用以区别用户身份、和对应的权限和信息,设计出一套安全的登录方案尤为重要,接下来我介绍一下常见的认证机制的登录设计方案。 方案设计 HTTP 是一种无状态的协议,客户端…...

如何在 Qt 的 QListWidget 中逐行添加和显示数据
文章目录 如何在 Qt 的 QListWidget 中逐行添加和显示数据目标实现步骤1. 在 Qt Designer 中添加 QListWidget2. 在代码中逐行添加数据示例代码 代码解析3. 使用自定义项 运行效果总结 如何在 Qt 的 QListWidget 中逐行添加和显示数据 QListWidget 是 Qt 提供的一个非常方便的…...