1、assert()使用
- assert宏的原型定义在<assert.h>中,其作用是如果条件返回错误,则终止程序执行
- 当表达式expression为假时,输出错误信息:
#include <assert.h>
#include <iostream>
using namespace std;
int main()
{
int a = 1, b = 2;
assert(a == b);
cout << "hah" << endl;
}
Assertion `a == b' failed.
- 当表达式expression为真时,正常输出:
#include <assert.h>
#include <iostream>
using namespace std;
int main()
{
int a = 1, b = 1;
assert(a == b);
cout << "hah" << endl;
}
hah
- 频繁的调用assert()会极大的影响程序的性能,增加额外的开销,在调试完成后,可以通过在 #include <assert.h> 语句之前插入 #define NDEBUG 来禁用assert()的调用
#define NDEBUG
#include <assert.h>
2、随机数种子
srand((unsigned int) time(NULL));
3、Boost库简单应用
#include <boost/algorithm/string.hpp>
string op = "HHAATT";
boost::to_lower([&]op); // hhaatt
4、C++中optional类(c++17引入)
- 判断返回值是否为空
4、类型转换
- C++标准库方法stoi(),stod(),stof()等
5、json使用
- json可以把内存或程序里数据对象,转换为字符串的工作
#include <nlohmann/json.hpp>
#include <fstream>
// 保存
nlohmann::json root;
for(auto &book : books)
{
nlohmann::json b;
b["name"] = book.name; // 双引号中名字可以自定义
b["author"] = book.author;
b["remain"] = book.remain;
root.push_back(b); // 添加对象到root
}
ofstream fout("./books.txt");
fout << root;
fout.close();
// 读取
ifstream fin("./books.txt");
nlohmann::json root;
fin >> root;
fin.close();
books.clear(); // 清空容器
for(auto &b : root)
{
Book book;
book.name = b["name"];
book.author = b["author"];
book.remain = b["remain"];
// json在保存的时候是什么类型,读取的时候会自动转换为该类型
books.push_back(book);
}
6、filesystem(C++17)
#include <filesystem>
// 判断文件是否存在
if(!std::filesystem::exists("./books.txt"))
return;
7、Point2f转换为 [] 访问
Point2f pt;
auto arr = reinterpret_cast<array<float, 2> *>(&pt);
(*arr)[0];
8、遍历容器中的值
-
for(auto x : str)是利用x生成str中每一个值的复制,对x的赋值不会影响到原容器
-
for(auto &x : str)是利用x生成str中每一个值的引用,对x的操作会影响到原容器
#include<bits/stdc++.h>
using namespace std;
int main(){
string str = "Hello";
for(auto x : str)
{
// 利用x遍历容器str中的每一个值
x = tolower(x);
}
cout<<str;//仍然是"Hello"
}
#include<bits/stdc++.h>
using namespace std;
int main(){
string str = "Hello";
for(auto &x : str)
{
// 这里加了&,表示对x的操作可以影响到容器str
x = tolower(x);
}
cout<<str;//变成小写"hello"
}
9、字符大小写转换
- tolower()函数是把单个字符转化为小写字母
- toupper()函数是把单个字符转化为小写字母
#include <iostream>
using namespace std;
int main(int argc, char **argv)
{
string str = "abcDEF";
for (int i = 0; i < str.length(); i++)
{
str[i] = tolower(str[i]);
}
cout << str << endl; //abcdef
for (int i = 0; i < str.length(); i++)
{
str[i] = toupper(str[i]);
}
cout << str << endl; //ABCDEF
return 0;
}
- transform函数可以一次性将字符串转换
#include <bits/stdc++.h>
using namespace std;
int main(int argc, char **argv)
{
string s = "HELLO";
transform(s.begin(), s.end(), s.begin(), ::tolower);
cout << s << endl; //输出hello
string s2 = "hello";
transform(s2.begin(), s2.end(), s2.begin(), ::toupper);
cout << s2; //输出HELLO
return 0;
}
10、纯虚函数与抽象类
- 虚函数在定义时前面加上virtual
- 纯虚函数就是没有结构体,同时在定义的时候,其函数名后面加上“= 0”
- 把包含纯虚函数的类称为抽象类,抽象类无法实例化对象;抽象类的子类也可以是抽象类;对于抽象类的子类来说,只有把抽象类中的纯虚函数全部实现后,这个子类才可以实例化对象
- 虚函数作用:为了方便使用多态特性
class Cman
{
public:
virtual void Eat(){……};
void Move();
private:
};
class CChild : public CMan
{
public:
virtual void Eat(){……};
private:
};
CMan m_man;
CChild m_child;
//这才是使用的精髓,如果不定义基类的指针去使用,没有太大的意义
CMan *p ;
p = &m_man ;
p->Eat(); //始终调用CMan的Eat成员函数,不会调用 CChild 的
p = &m_child;
p->Eat(); //如果子类实现(覆盖)了该方法,则始终调用CChild的Eat函数
//不会调用CMan 的 Eat 方法;如果子类没有实现该函数,则调用CMan的Eat函数
p->Move(); //子类中没有该成员函数,所以调用的是基类中的
- 纯虚函数作用:同虚函数,纯虚函数只定义了函数体,没有实现过程(可以理解为想描述一些事物的属性给别人,而自己又不想实现,就可以定义纯虚函数)
11、静态成员变量、静态成员函数
- C++中静态成员变量与静态成员函数的语法:
#include <iostream>
#include <string>
using namespace std;
class test
{
private:
static int m_value; //定义类的静态成员变量
public:
static int getValue() //定义类的静态成员函数
{
return m_value;
}
};
int test::m_value = 12; //类的静态成员变量需要在类外分配内存空间
int main()
{
test t;
cout << t.getValue() << endl;
system("pause");
}
- 类的静态成员变量属于类的成员而不是对象,供所有对象共享,存放于全局区,因而不计入类的内存计算。使用静态成员变量实现多个对象之间的数据共享不会破坏隐藏的原则,保证了安全性还可以节省内存。静态成员变量可以通过类直接访问
- 静态成员函数主要是为了处理静态成员变量
- 普通函数名前加static,表示该函数失去了全局可见性,只在该函数所在的文件作用域内可见
12、命名空间的重要性
- 可以使不同用户在相同工程下的名称相同的变量分隔开来,这样可以使效率更高
- 使用命名空间可以更为清晰明了的表明用户定义的变量/函数在哪个地方,使得其他观看者更为清除的观赏代码
- 不同作用域下可以使定义的变量函数更为严谨