预处理
预处理有3个经常用的东西#include
,#define
,#if #endif
其实预处理的意思大概就是,原文替换
有一个a.h文件
void test(){
return ;
}
有一个a.c文件
#include "a.h"
void test2(){
test();
}
经过预处理后,实际的a.c文件是这样的
void test(){
return ;
}
void test2(){
test();
}
编译
编译其实就是把源代码.cpp
转换成二进制代码.obj
关注点是,应该明白声明(declaration)
和定义(definition)
的区别。
- 声明指的是告诉编译器,这个东西是存在的
- 定义就是,这个东西到底是什么
链接
把一个项目的所有的.obj
链接成一个可执行程序.exe
static
在函数前,表示这个函数只会在这个文件被使用(免除链接阶段)
inline
在函数去,这个函数被其他函数调用时效果和#include
一样
神秘错误
有个文件Log.h
#pragma once
#include <iostream>
void Log(const char* message) {
std::cout << message << std::endl;
}
另一个文件Log.cpp
#include "Log.h"
void init_log() {
Log("init_log");
}
还有一个文件math.cpp
#include <iostream>
#include "Log.h"
static int multiply(int a, int b) {
int result = a * b;
Log("multiply");
return result;
}
int main() {
std::cout << multiply(5, 8) << std::endl;
}
在链接阶段会报错,因为#include
的特性,实际上Log
函数被定义了2次。
解决办法
- 使用 static 关键字
- 使用 inline 关键字
- 头文件不要定义!!!
头文件
#pragma once // 改头文件只包含一次,所以不会重复声明
#ifndef _LOG_H // ifndef 和 #pragma once的作用相同
#define _LOG_H
#include <iostream>
inline void Log(const char* message);
struct player{};
#endif
引用
c++的引用其实是一种semantic sugar
。
引用相当于给变量起一个别名。
因此,引用在声明时就必须有一个定义,并且这个定义在这个程序中无法被更改
int x = 6;
int b = 3;
std::cout << x << std::endl;
int& ref=x; //这个程序中,ref只能是x的别名
ref= b; //相当于 x = b
其实引用这种用法在普通编写代码时显得没有必要,但是在函数传参中就比较有用了。
int increment(int& x) {
x++;
return 0;
}
int main() {
int x = 6;
int b = 3;
std::cout << x << std::endl;
int& ref=x;
increment(x);
std::cout << x << std::endl;
}
用这种办法,相比于指针,使得代码清晰好看了不少(😀其实这就是引用的作用)
引用能做的,指针也能做;引用不能做的,指针也无法做到
实际上引用的底层逻辑就是指针
类
类是面向对象编程的一种概念
类是一种物体的宏观描述(data 加 function)
class player {
public:
int x, y, speed;
void move(int xa, int ya, int speeda) {
x += xa * speeda;
y += ya * speeda;
}
};
int main() {
player playerx, playery;
playerx.x = 1;
playerx.y = 1;
playerx.speed = 2;
playerx.move(2, 4, 5);
std::cout << playerx.x<< std::endl;
}
class和struct的区别
其实唯一的区别是默认的可见性。
class默认私有(private),struct默认公开(public)
struct player {
int x, y, speed;
void move(int xa, int ya, int speeda) {
x += xa * speeda;
y += ya * speeda;
}
};
int main() {
player playerx, playery;
playerx.x = 1;
playerx.y = 1;
playerx.speed = 2;
playerx.move(2, 4, 5);
std::cout << playerx.x<< std::endl;
}
这段代码跟上一段代码是同一个效果。
虽然实际上struct
和class
在技术上没有区别,但是大多数人都对它们两个做了区分。
- struct用在少量的数据操作上,class用在比较复杂的行为上(比如玩家的属性,功能,etc)
- 用在继承(inherit)上,普遍用法都是class
如何使用类
#include <iostream>
class Log {
public:
const int LogLevelError = 0;
const int LogLevelWarning = 1;
const int LogLevelInfo = 2;
private:
int m_LogLevel;
public:
void SetLogLevel(int level) {
m_LogLevel = level;
}
void LogError(const char* message) {
if (m_LogLevel >= LogLevelError) {
std::cout << "[ERROR]: " << message << std::endl;
}
}
void LogWarning(const char* message) {
if (m_LogLevel >= LogLevelWarning) {
std::cout << "[WARNING]: " << message << std::endl;
}
}
void LogInfo(const char* message) {
if (m_LogLevel >= LogLevelInfo) {
std::cout << "[INFO]: " << message << std::endl;
}
}
};
int main() {
Log log;
log.SetLogLevel(log.LogLevelWarning);
log.LogError("hello");
log.LogWarning("hello");
log.LogInfo("hello");
}
c++中的全局静态
static int i;
static void func(){
;
};
用在全局变量当中表明只在当前翻译单元(即当前文件中可见
c++类中的static
struct Entity {
static int x, y;
static void print() {
std::cout << x << y << std::endl;
}
};
int Entity::x;
int Entity::y;
表明所有类的实例共享这一个静态变量。
使用时需要用如下格式:
Entity::x = 4;
Entity::y = 5;
Entity::print();
注意,类当中的静态函数不能访问非静态变量,因为他不知道非静态变量指向谁
c++中的局部static
void func(){
static int i =0;
i++;
std::cout<<i<<std::endl;
}
局部static只会创建一次并一直到程序终止时都存活,只不过只能在当前函数中访问它。
构造
构造函数,当声明一个类实例时自动调用,初始化类的某些数据和功能。
#include <iostream>
class Entity {
public:
float x, y;
Entity() { // 必须与类名称同名
x = 0.0f;
y = 0.0f;
}
Entity(float X, float Y) {
x = X;
y = Y;
}
void print() {
std::cout << x <<','<< y << std::endl;
}
};
int main() {
Entity e(3,4);
e.print();
}
析构
#include <iostream>
class Entity {
public:
float x, y;
Entity() {
x = 0.0f;
y = 0.0f;
}
Entity(float X, float Y) {
x = X;
y = Y;
}
~Entity() {
std::cout << "Destory Entity" << std::endl;
}
void print() {
std::cout << x <<','<< y << std::endl;
}
};
void function() {
Entity e(3, 4);
e.print();
e.~Entity();
}
int main() {
function();
}