c++ 预处理编译链接 & 引用 & 类 & static & 构造 & 析构

2023-02-21

预处理

预处理有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)的区别。

  1. 声明指的是告诉编译器,这个东西是存在的
  2. 定义就是,这个东西到底是什么

链接

把一个项目的所有的.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次。

解决办法

  1. 使用 static 关键字
  2. 使用 inline 关键字
  3. 头文件不要定义!!!

头文件

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

这段代码跟上一段代码是同一个效果。
虽然实际上structclass在技术上没有区别,但是大多数人都对它们两个做了区分。

  1. struct用在少量的数据操作上,class用在比较复杂的行为上(比如玩家的属性,功能,etc)
  2. 用在继承(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();

}