IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发工具 -> c++&visualStudio学习笔记 -> 正文阅读

[开发工具]c++&visualStudio学习笔记

5 c++如何工作

源文件就是文本文件转化到可执行的二进制文件或者程序,然后源文件会传到编译器,然后编译成二进制文件(binary)

 #include<iostream>

int main()
{
	std::cout << "hello world " << std::endl;
	std::cin.get();
}

5.1include

首先这其中· #include称为预处理文件,任何以#开始都是预处理文件,当编译器收到一个源文件时,它第一件事就是预处理你所有的预处理指令。这就是为啥·叫预处理,因为整的发生在编译之前。
这里用include,include就是找到一个文件,这里是找一个叫iostream,该文件里所有内容会被复制到目前这个文件里。
你include的文件被称为头文件,我们之所有include头文件iostream是因为我们需要一个函数(function):cout的申明。cout可以打印东西到控制台console,然后我们有了这个main函数,main函数相当重要。

5.2main

main函数被称作入口点(entry point)也就是说我们运行程序时,计算机会从该函数里的代码开始执行。
这其中main的定义是int,然而我们没有返回一个整数(integer)。
这是因为main是个例外,你不需要从主函数返回任何类型的值,如果你不返回任何值,它会返回0,这只适合于main函数

5.3 <<

在这里插入图片描述
这些向左的带角的括号,看起来像左移位符号(bit shift),其实是被重载的符号,你得把它想成一个函数,我知道他看起来像运算符,但实际上,运算符就是函数,所以这种情况下和cout.print一模一样
这里目的即使把hello world 传入 cout,cout把它打印在控制台里。然后传入endl,end line告诉控制台前进到另一行。

5.3 linker链接器

1首先 include iostream,即使预处理,会在编译文件之前被评估。即使把iostream中内容拷贝到这个文件里。
2当我们头文件被评估后,我们的文件会被编译,这个阶段,编译器会把我们的c++转化成实际的机器码。
所有cpp文件都会被编译,而头文件不会,只有cpp,头文件在预处理被include到头文件里,那是他们被编译的时候,所以我们有一堆cpp文件被编译,而且它们是一个个被单独被编译的。每个cpp文件会被编译成一个object文件,如果扩展名的话,用Windows编译器是.obj,当有了一个个obj时候,也就是cpp被编译过后的结果,我们得有办法把他们联系起来,组成exe。这时我们得朋友linker(链接器)就有用武之地
你可以在linker标签下看它的设定,但基本就是把所有obj拿来的然后联系起来
linker的作用是把所有obj连成exe,
error list 的工作原理是,解析(parse)output窗口,找error关键字,然后从哪找信息,放入list,功能简单,output功能比较全面
在这里插入图片描述
此处双击问题即可到发生错误的地方。
当你单独编译一个文件,linking显然不会发生,因为你单独一个文件。
如果我们有多个c++文件呢?
假设我们有打印hello world 到控制台,但不想用cout,用自己的logging函数,这就需要包装logging函数

我们来写log函数,会接受cstring作为参数,取名,message,并打印message到控制台。
在这里插入图片描述
此时我们可以把log放到另一个文件
在这里插入图片描述
新建一个log.cpp会发现cout不是STD的member,这基本上说不懂cout是啥,这要是没有吧cout声明include进来。
c++中每个symbo都需要某种声明,cout是main里include文件里定义的一个函数,也就是iostream
把#include剪切入log.cpp再次编译成功了
回到main我想调用log函数,ctrl+f7编译失败,不知道cin,加入#include,会发现log还是找不到,我们把函数从一个文件移动到另一个。
发生错误的原因是它识别不出log,所以我们需要通过一个声明(declaration)来解决。声明从字面意思,就是声明log是一个存在的东西。有点像承诺,告诉编译器有一个函数叫log,编译器就真的相信了。因为编译器根本不关心resolving(解析)log到底被哪定义的。
这里有两个词,declaration(声明)和definition(定义)申明就是这个symbol真的存在,定义是说这个函数到底是什么,这个函数的主体。

这中间有个疑问,如何能确定有这个函数,这时候link就有用了。
当我们文件被编译后,linker就会去找log的定义,然后跟我们main里调用联系起来。
如果找不到定义,就会得到linker error
在这里插入图片描述
我们可以看到两个obj因为,每个编译cpp都会产生obj,然后linker会串成exe

7 C++链接器linker是如何工作的

linking是从c++源码到二进制可执行文件的一个过程。
我们编译后会通过一个叫做链接的过程,链接的主要工作是找到每个符号和符号的位置并把它们链接在一起。
我们需要一种方法将这些文件链接到一个程序。即使没有外部文件里的函数,比如你已经把一个程序写在一个文件里了。应用程序仍需要知道入口点在哪里

7.1案例

在vs中我们有一个非常简单的项目,只包含一个源文件math.cpp.
在这里有两个函数log和multiply,multiply实际上调用了log函数,打印出multiply这个单词到控制台。然后返回a*b
在这里插入图片描述
编译有两个阶段-编译和链接。
你可以对其进行区分,如果你按ctrl-F7或者按下编译按钮,只有编译会发生链接完全不会发生。然而如果你build你的项目或者按F5运行它会编译然后链接。
如果你按crl+f7可以发现没发生任何错误
如果你按build会发现得到一个链接错误,缺少入口函数,我们的主函数。
因为我们的编译分为两个阶段,如果编译中出现错误,错误会以c开头,如c243.
如果链接中出现问题会以LNK开头
你在文件的属性,可以知道配置类型是exe,exe必须要有一个入口点。
在这里插入图片描述
在这里插入图片描述
在一个文件中即可build成功。
如果这些函数存在多个文件中。如把log函数加入log.cpp中,再执行会报错,因为找不到名为log的函数
在这里插入图片描述
所以把声明加入math.cpp中可以发现
在这里插入图片描述
编译成功

10 头函数

在C++基础上,头文件传统上是用来申明某些函数类型,以便用于整个程序中。在链接器章节中我们知道,为了让我们知道函数和类型的存在,我们需要某种声明。
我们需要一个共同的地方存放函数声明,只是声明,没有实际的定义,没有函数的主体。

10.1案例

假设在主文件生成一个c++文件定义了Log函数
main.cpp

#include <iostream>
void Log(const char* message)
{
	std::cout<<message<<std::endl;
}
int main()
{
	std::cout<<"hello world "<<std::endl;
	std::cin.get();
}

在log.cpp中
在这里插入图片描述
在这里还有一个log.cpp中使用了Log函数,我们拿到一个错误,log函数不再该文件中,该文件不知道log函数的存在。我们在main中可以正常使用,在log.cpp中会报错。所以log.cpp到底需要沙漠才不会报错。
如何才能告诉它,log函数存在,只是区别于别的地方。
这时是函数申明的使用之地。
在这里插入图片描述
加入函数声明后可以正常使用按ctrl+f7可以编译。对项目编译也可以看到链接成功,因为可以找到log函数。
我们告诉了log.cpp那个函数存在某处,如果我们创建另外一个文件呢?我们创建一个别的文件,然后使用这个log函数呢?
这意味这个void log声明可以到处复制黏贴吗?
答案是的,你确实需要怎么做,但是有一个方法可以让一切简单一点。
就是头文件

10.2头文件

头文件一般被include到cpp文件里面,基本就是复制和黏贴进cpp文件里。我们创建一个头文件,上图中的文件夹都是过滤器并不是真正的文件夹。我们可以在资源文件下创建一个头文件。其实就是无论在什么地方创建头文件都没关系
在这里插入图片描述
在这里插入图片描述
此时我们将头文件剪切放在这里。我们的头文件log.h,我么可以在任何想用log函数的地方include它,然后显然他会帮我们做哪些我们不想人工做的事。
其实我们还可以include“log.h”到main.cpp,main.cpp包含实际的函数定义,所以我们并不需要它,我们反正可以调用log。但加进去也不会报错。

如果我们在main中调用initLog会报错所以我们需要去log头文件把函数签名加进去。

void Log(const char* message);
void initLog();

此时可以在main中调用

10.3pragma once

在这里插入图片描述
pragma once意思是只include这个文件一次,是一种头文件保护符
他所作的是防止我们把单个头文件多次include到一个单一翻译单元中。
其实不会防止我们把头文件include到程序各处,只防止到一个翻译单元里,也就是一个单独的cpp文件,原因是我们不小心把一个文件多次include到一个翻译单元中。我们会得到一个重复的错误,因为我们会多次复制和黏贴那个头文件。一个比较好的办法是我们创建一个Struct
在这里插入图片描述
我们可以创建一个struct player{},如果我们把这个文件,两次应付得到一个翻译单元,并且没有头文件保护。他会真的include这个文件两次,也就是我们会有两个structs,他们有相同的名字player。
如果我们去掉#pragma once 并如下图引入两次Log.h。
在这里插入图片描述
我们会得到一个player structure重复定义的问题。
也许会觉得自己不会干这个种事,但是c++种会出现套娃的问题。
比如有一个头文件player include log,然后player 又被inlude到其他文件。假如我们创建一个common也包含log.h。如下图把pragam once 注释掉
在这里插入图片描述
在这里插入图片描述
此时main中也会出现同样问题。
如果log.h不再一个文件夹中,比如它目前存在log.cpp的上一级目录中,可以使用…/来返回上一级目录
在这里插入图片描述
iostream“”也可以用来告诉编译器位置,可以在任何地方用,我们可以把iostream换成引号,将完全没有问题。所以方括号只用于编译器include路径,引号用于所有。但我一般只喜欢将它用于相对位置,还不如方括号。

25构造函数

25.1为什么需要构造函数

构造函数是每次在实例化时运行
在这里插入图片描述
在这里插入图片描述
这里实例化Entity并为他分配内存,实际上没有初始化那个内存,如果在main函数中访问X会报错
在这里插入图片描述
未初始化局部变量
在这里插入图片描述
初始化init函数会有很多多余的操作也不清爽。
在这里插入图片描述

25.2构造函数

构造函数是一种特殊的方法,每次构造一个对象都会调用的方法。构造函数没有返回类型且名称必须与类的名称相同。在java和python中会初始化为0但是c++不会,需要手动初始化所有基本类型,否则会设置为留在内存的其他值。
当写一个同名方法,叫函数重载,即有相同的函数名,但不同参数对应不同的函数版本
在这里插入图片描述

25.3不使用构造函数

25.3.1方法1放入private

例如一个类只有静态方法,我们只想让其使用静态方法,不希望创建实例,放入private可以发现不能访问构造函数
在这里插入图片描述

25.3.2方法2使用delete

在这里插入图片描述

34const

const基本就是做出承诺,承诺某些东西是不变的。
它只是一个可以绕开的承诺,你可以绕开承诺
这个承诺好处是可以简化很多代码

34.1 常数

在这里插入图片描述
这里是无法改变的,做出承诺从语法上说这个整数是一个常数

34.2指针

当你声明一个指针,没有用const会在堆上生成,这里我可以做两件事,逆向引用a,然后将它设为一个值比如2,然后我们可以做另一件事就是重新分配实际的指针,这样他就指向别的地方,比如&MAX_AGE为了绕开const限制
这里我们可以做两件事,我们可以改变指针内容,我们也可以改变指向的地址
在这里插入图片描述

在这里插入图片描述
1const 放在*前
不能修改指针指向内容
在这里插入图片描述

const int* a=new int

这里尝试改变a指向内容会发生错误,当改变a本身是不会报错的
2 const放在*后
在这里插入图片描述
我可以改变a的指向内容,但我不能把实际指针本身重新赋值,指向别的东西
这两个效果是一样的,关键是 * 前还是 * 后
在这里插入图片描述
3 *前后都有
在这里插入图片描述
不能改变a的指向内容,也不能把实际指针本身重新赋值,指向别的东西

34.3类和方法

放在函数名后
在这里插入图片描述
在这里插入图片描述

这个方法不会修改任何实际类,我们不能修改类成员变量
不能再setter中用函数名后的const,这样我们不能修改类中的成员变量,通常用在GetX中
在这里插入图片描述
如果m_x是一个指针,想让它保持不变,这样会写三个const,这意味着返回了一个不能被修改的指针,指针内容也不能被修改,这个方法承诺不修改类中变量

在这里插入图片描述

34.4引用

在这里插入图片描述

引用没有指针本身和指向内容的区别了,因为引用就是内容
如果把const去掉会报错,因为无法确定GetX函数不会写入Entity类,有时候会写两个GetX一个带const,一个不带

在这里插入图片描述

34.5mutable

当函数为const,但你有些调试的参数可以用mutable。
mutable允许函数是常量方法,但可以修改变量
在这里插入图片描述

  开发工具 最新文章
Postman接口测试之Mock快速入门
ASCII码空格替换查表_最全ASCII码对照表0-2
如何使用 ssh 建立 socks 代理
Typora配合PicGo阿里云图床配置
SoapUI、Jmeter、Postman三种接口测试工具的
github用相对路径显示图片_GitHub 中 readm
Windows编译g2o及其g2o viewer
解决jupyter notebook无法连接/ jupyter连接
Git恢复到之前版本
VScode常用快捷键
上一篇文章      下一篇文章      查看所有文章
加:2022-12-25 11:29:10  更:2022-12-25 11:31:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年9日历 -2024/9/8 7:33:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码