一、函数声明
在一个cpp 中 要用到另外一个cpp中的函数或者结构体等,可以使用声明
声明:在要用到的cpp文件中,再写一遍头文件里的声明即可 (只是说这个函数存在)
定义:这就是这个函数(包含函数的实际主题{})
编译器其实不知道声明的函数在什么地方,在编译时编译器回去找定义,如果找不到定义就会报错
二、编译
编译:代码进行预处理
已经发生的预处理器评估结果的文件是干嘛的?
-
#define 单纯的替换
-
#if #endif #ifdef #ifndef 可以快速的屏蔽代码块
-
#include 可以包含其他头文件代码,单纯的放在#include的位置
编译器先编译原文件 编译成目标文件(汇编语言),再通过目标文件链接成.exe文件
每一个文件都编译成一个*.obj 目标文件,再链接起来生成可执行文件,通过Main()函数作为开口.
入口点,不一定是main函数?
为解析的外部符号:链接器找不到它所需要的东西会报错,看声明函数是否匹配
三、链接
链接:每一个文件都编译成一个*.obj 目标文件,再链接起来生成可执行文件
常见的链接错误:
-
在.h文件中写好了具体函数声明和主体,在多个cpp文件中 #include 了 该文件,可能会报重复定义的的问题
解决方案:
-
具体的函数主体,放在相关cpp文件中,.h文件只放置函数声明
-
用static变成静态函数,那么不同的ccp文件中都会独立拥有自己版本的函数,对任何其他目标摁键都不可见。
-
用inline 内联函数声明,会将实际的函数体,类似手写了一遍并调用,那么每一个#include 的cpp内部都重写了一份,替换调用
-
四、变量
变量会占内存容量,变量的区别:字节大小不同
五、函数
函数主要的目的是为了防止代码重复 ,函数指定了返回值,却没有返回时,只有再debug模式下会报错。
声明:头文件
定义:cpp文件
六、头文件
#pragma once // 发送给编译器或预处理器 :头文件保护,(不能包含到单个(再单个文件包含多个)cpp文件中)这会导致重复包含,
#ifndef
没有定义的话
#ifdefine
定义了的话
#endif
推荐使用 #pragma once
include: 是将文件粘贴复制到包含位置中
七、Visual Studio 中调试C++
计算机总是对的(99%)
断点
注意想要单步调试:需要把优化给关了(属性->c++->优化 禁用),不然可能直接就结束了
F9 :设置断点(切换)
F10 :步入 (会一步步进入函数)
F11:步过(会跳过该函数到下一行)
调试器会中断,看内存中发生了什么
查看内存
内存视图:可以查看整个程序的内存数据
调试 窗口 内存 和 内存1
反汇编:调试没有源代码的源代码时, 可以快速查看编译器实际生成的代码
避免使用 if else
整个项目解决方案,C++配置
在属性常规里面可以设置 输出目录 :所有的生成文件都会放在该目录下
可以去属性 配置属性->常规 里边
一般所有的cpp, .h 文件可以放在这里
存放最终生成的可执行文件(或 DLL、lib 等)。
🔹 详细说明:输出目录
编译完成、链接结束后生成的结果文件,比如:$(SolutionDir)bin$(Configuration)\ 默认路径可以在中间添加自定义的文件夹 例如:$(SolutionDir)bin$(Configuration)\
-
.exe(可执行文件) -
.dll(动态链接库) -
.lib(静态库) -
.pdb(调试符号文件)英文名: Intermediate Directory(或 IntDir) 主要功能: 存放编译过程中的中间文件。
🔹 详细说明:中间目录
当你在 VS 中编译(Build)一个 C++ 项目时,编译过程是分为几个阶段的:
-
编译(Compile)阶段: 每个
.cpp文件会被编译器(cl.exe)单独编译成.obj(目标文件)。 -
链接(Link)阶段: 链接器(link.exe)会把所有
.obj文件和库文件合并成最终的可执行文件(或 DLL)。
这些
.obj文件、预编译头文件.pch、以及临时生成的.tlog、.idb等文件—— 👉 都会存放在 中间目录(IntDir)下。 -
一般项目设置思路(作为一个):先在真实的文件路径中(项目文件的路径中)添加一个src或者source文件夹用于包含:所有的源代码和头文件等内容都在该文件中(这样项目文件和项目中可能被用到的其他资源能够很好的被分隔到文件夹中)
(可以在磁盘里进行操作,也可以通过vs拖动添加)
Visual Studio 默认: 会把 中间文件放入 项目目录中名为debug 的文件夹中
实际的最终可执行二进制文件放入了解决方案目录(在根目录)中名为debug的文件夹中
可以创建模板 自己设置输出目录
最后: 为每个配置放入单独的文件夹
八、C++中的for 、while 循环
注意:
1、在写for 循环的时候 一定要注意 判断数据的类型要保持一致性,不然可能会出现内存泄漏
long sum = 1000;
for(int i = 0 ; i < sum; i++)`
{
}
由于long 和 int 所占的字节数不一样,超过int限定数据,数据会变乱
2、只需要一个判断条件时 用 while
3、do {}while () 不管什么情况主体都会执行一次
九、C++ 中的控制流
break
Continue
return
十、C++中的指针
指针是一个整数,一个存储内存地址的数字
0是一个无效的内存地址 (我们不能从0内存地址进行读取和写入 不然程序会崩溃, 0 = null nullptr是 C11 中的定义)
*& = 变量值
不同类型的指针只能表示:占有多少个字节的整数 ,永远都是一个整数
注意:当使用了 new 关键字 在完成数据操作之后一定要进行删除 delete (每次写完代码之后都需要
十一、C++中的引用
引用只是伪装下的指针
注意:
-
指针可以创建一个新的指针变量,将其设置为空指针,但是 引用必须引用一个已经存在的变量
-
引用本身并不是新变量,实际上不占用内存,不占用内存空间
-
当声明一个引用时,实际要分配给某一个变量, int& ref = a; //声明的同时就要绑定
-
当引用以及赋值绑定了之后,就不能再绑定其他变量了 ,只是变成了一个变量的值 赋值给了这个别名而已
-
指针就可以在中途改变 指向的地址数据 int *p = &a; p=&b; 这样就改变了
如果&在类型后面 ,说明这是一个引用声明,如果在 int *p= &a ; 等号右边说明这是在取地址
int a = 5;
int b = 9;
int& ref = a; //本质上是创建了一个别名, ref本质上是a 的别名,对ref的操作就是对a进行操作
ref = b; //这是错的, 当引用确定了之后就不能再赋值其他的地址了 实际上是 a =b; a的数据值变成了9
void Increment( int& value) //Increment(a)
//数据传递给函数可以通过引用 改变传入数据的具体值,因为引用就是实参的别名
{
value++;
}
//或者用指针
void Increment(int* value) //increment(&a)
{
(*value)++; //如果不做解引用,*(value++) 默认是从右往左,这样加的就是内存地址,整个数据就会变成乱的 有C++表可以查
}
十二、C++中的类(面向对象编程)
默认情况下未标明,都是private 的 而结构体默认时public
class 与 struct 的区别
-
class 默认是私有的 struct默认是共有的, 唯一区别
-
C语言中有struct 没有 class ,这样可以使得C与C++之间进行兼容
-
(个人的编程风格问题)不建议再结构体中使用继承。如果说有一个完整类层次结构或者某种继承层次结构类,最好使用class
-
如果只是想表现 一些数据,就用结构体
-
如果有一个充满功能的完整类,还有可能用到继承,就用类
日志系统:error warnig message trace 级别
-
在设计类时:需要思考设计类实际上如何工作,创建新类或设计API:通过其用法,去构思 先构思 最表层需要用到的接口, 再往内部进行设计需要用到哪些基本接口未最表层直接会使用的函数服务;
-
m_ 表示这是一个私有的类成员变量
-
在设计一个类的时候可以 写多个public 按照:比如说 公共方法一个地方 公共变量一个地方 公共静态变量一个地方 这个样子 可以分类快速找到
十三、C++中static关键字
在类或结构体外部使用static
只能在定义的翻译单元中可见 :一个 .cpp 文件(以及它包含的所有头文件) → 就是一个翻译单元。
Static.cpp (一个翻译单元) static int value = 5; //static 类似与类中 private类型,链接器会自动忽略 main.cpp(另一个翻译单元) int value = 2; // 这种情况 是不会报错的,因为链接会忽略 static.cpp 中的同名静态变量 //如果 static.cpp 中 int value = 5 ,在main.cpp 中可以用一个extern 外部变量声明,这样会自动链接到static.cpp 中的同名变量
-
如果在一个.h文件里面 声明了一个 static静态变量, 分别在两个cpp文件里边引用了.h文件,这两个cpp里用的static变量是分别独立的
-
,使用extern外部变量声明可以共用,extern int a =10;
-
在使用过程中不需要变量是全局的,应该尽可能地使用static,(全局作用域中声明没有static的内容 连链接器将在翻译单元之间捕获->全局变量)
在类或结构体内部使用static
在创建的类和结构体的所有实例中,该静态变量只有一个实例(值会保留且共用)
通过类实例引用该变量没有意义,因为 类或结构体内部的static 只有一个全局实例, 可以直接通过类名引用
静态方法:
-
无法通过类实例访问,直接通过 类名::调用
-
不能编写引用类实例的代码(没有可以引用的类实例)
-
在类内部和结构体内部的静态函数里面只能用静态变量 在静态函数里面 无法引用非静态成员(静态方法没有类实例) 但是可以通过传参数进行访问
stuct A
{
int x,y;
static void print()
{
std::cout<<x<<" "<<y<<" "<<std::endl; //这里 x,y 不是静态变量,是无法正确识别的
}
}
static void print(A e)
{
std::cout<<e.x<<" "<<e.y<<" "<<std::endl; //可以通过传入参数的形式进行访问
}
十四、C++中的局部静态变量
生命周期:可以在内存中保留多长时间才会被删除
作用域:可以在什么地方实际访问该变量
单例类是只有一个实例存在的类
在程序的某个时刻调用一个静态初始化函数来创建所有对象,使用静态的get方法可以获取到这个单例类的唯一实例,再进行操作。
class Singleton
{
private :
static Singleton* s_Instance;
public:
static Singleton&()
{
return *s_Instance;
};
void hello()
{
}
}
//方法二
public:
static Singleton& Instance() //这里返回的是地址,如果返回一个局部变量会有bug(该情况可以添加static 使得生存周期为永久)
{
if (!s_Instance)
s_Instance = new Singleton(); //定义且初始化
return *s_Instance;
}
static Singleton& get() //返回的地址
{
Singleton instance;
return &instance;
}
};
//初始化这个静态变量的单例
Singleton* Singleton::s_Instance = nullptr; //这里不是访问而是定义
//对于编译器来说必须要定义,为其分配空间才能正常运行
main.cpp
Singleton::Get().hello(); //获取唯一实例并调用类函数
c++中的枚举变量
如果想用整数表示某些状态或特定值时,可以考虑枚举变量
enum Exampl//默认从0开始,指定后续值默认加1 还可以指定类型 【:char 、unsign char】(不能为float 只能为整数)
{
A,
B,//命名时可以添加 level前缀 levelB
C
};
// enum Exampl:char
//注意 Exampl 不是一个命名空间, 所以 当需要赋值时可以直接使用枚举的内部变量,如果是类外使用的话(类名::具体枚举常量)
int main()
{
Exampl value = B;//枚举类型的变量只能赋值定义好的枚举值
}
729

被折叠的 条评论
为什么被折叠?



