c++笔记

记载一些学习C/C++语法,库函数,开发框架等

1. 好用的方法:

1. PixmapToRound函数

将QPixmap的图像转换为圆形,美化界面用,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#ifndef ROUNDIMG_H
#define ROUNDIMG_H
#include <QPixmap>
#include <QPainter>
#include <QPainterPath>//此处radius是半径
QPixmap PixmapToRound(const QPixmap &src, int radius)
{
if (src.isNull())
{
return QPixmap();
}

//按比例缩放
QPixmap pixmapa;
if(src.width() != radius || src.height() != radius)
{
pixmapa = src.scaled(radius, radius, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
}
else
{
pixmapa = src;
}
QPixmap pixmap(radius,radius);
pixmap.fill(Qt::transparent);

QPainter painter(&pixmap);
painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);

QPainterPath path;
path.addEllipse(0, 0, radius, radius);
painter.setClipPath(path);
painter.drawPixmap(0, 0, radius, radius, pixmapa);

return pixmap;
}
#endif // ROUNDIMG_H

//示例:
QPixmap img;//上端圆形图片,用自己头像嘿嘿
img.load("://res/login.jpg");//图片加载
QPixmap pixMap= img.scaled(100,100, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
//50为圆形的半径
pixMap = PixmapToRound(pixMap, 50);
ui->label_img->setPixmap(pixMap);

2. 使用正则表达式规定输入规范

1
2
ui->lineEdit_1->setValidator(new QRegularExpressionValidator(QRegularExpression("[0-9]+$")));//只能输入数字,个数不限
ui->lineEdit_1->setValidator(new QRegularExpressionValidator(QRegularExpression("[A-Fa-f0-9]{1,12}")));//能输入数字和a-f大小写,控制个数不多于12个

3. 使用花指令增加逆向破解难度:

1
2
3
4
5
6
__asm__("test $0,%eax\n"
"jz label\n"
"add $0xff,%esp\n"
".byte 0xe8,0x80,0x80,0x80\n"
"label:\n"
);//破坏了堆栈平衡,以及插入了一些junkcode

4. 与数据库互通的一些操作:

CMakeList.txt文件里写入:find_package(Qt6 COMPONENTS Sql REQUIRED) target_link_libraries(TeamProject PRIVATE Qt6::Sql)

连接数据库,代码段里写入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void MainWindow::linkDatabase()//连接数据库
{
database=QSqlDatabase::addDatabase("QMYSQL");//QMYSQL对应数据库类型,此处为mysql
database.setHostName("192.168.76.1");//对应ip地址
database.setPort(3306);//对应开放的端口号
database.setUserName("root");//对应用户名,此处为root用户
database.setPassword("123456");//对应密码
database.setDatabaseName("test");//使用的数据库名称
database.open();//连接数据库
if(!database.isOpen())//判断是否连接成功
{
setWindowTitle("数据库没有连接成功呐!");
//exit(0);
}
}

5. 给Qt生成的可执行文件设置图标,以及窗口左上角图标:

给可执行文件设置图标,先在cpp同级目录下创建一个ico.rc文件(后缀一定要是.rc),然后再CMake.txt文件下写入文件编译区,然后再Source Files下找到该文件并写入 IDI_ICON_LOGO ICON DISCARDABLE "res/logo.ico",双引号里面是图标的相对路径,.ico文件可在 D:\Pixillion软件中进行图片格式转换。

窗口左上角图标设置:setWindowIcon(QIcon(":/res/R-C2.jpg"));

在Qt中调用其他系统命令或执行文件时,可用QProcess函数:

1
2
3
4
QProcess process(this);
QString str = QApplication::applicationDirPath();
str += "/firmware_upgrade_v1.0.0.exe";//子程序exe对应主程序exe的相对路径
process.startDetached(str);//startDetached使执行文件与主程序分离,主程序关闭并不影响子程序的运行,start与之相反。

6. 数据库查询和写入操作

1
2
3
4
5
6
7
8
9
10
QSqlQuery query;
QString s = QString("select * from users where id='%1'").arg(id);//查询语句
QString s2 = QString("INSERT INTO users (id,passwordMD5,`password`,name)VALUES ('%1','%2','%3','%4')").arg(user).arg(pwdMD5).arg(pwd).arg(name);//插入语句,此处按表中字段顺序插入对应值
query.exec(s);
if(!query.first())//如果查询不到
{}
else//查询到了
{}
//用query.value()函数等来访问查到的值
//注意一定要在query.first操作后访问query.value()的值,该操作的目的是让查询指针移动

7. QThreadPool线程池的使用

先创建一个继承QRunable和QObject的线程类,在类中定义一个public的void run()函数,然后在主线程创建类对象,用QThreadPool::globalInstance()调用类对象实现多线程,示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
thread1 *thread = new thread1;
QThreadPool::globalInstance()->start(thread);
//.h
#include <QObject>
#include <QRunnable>
class thread1 : public QObject,public QRunnable
{
Q_OBJECT
public:
explicit thread1(QObject *parent = nullptr);
void run();
signals:

};
//.cpp
#include "m_thread.h"
#include "gamehall.h"
thread1::thread1(QObject *parent)
: QObject{parent},QRunnable()
{
}

void thread1::run()
{
GameHall* gamehall = new GameHall();
gamehall->show();
// connect(gamehall,&GameHall::m_show,this,&MainWindow::Show);
}


2. Qt中一些好用的部件属性对应的qss代码:

1. LineEdit部件:

设置形成的是一个浅绿色圆角编辑框。

1
2
3
4
5
ui->lineEdit_1->setStyleSheet("font: 25 14pt '微软雅黑 Light';" //字体
"color: rgb(31,31,31);" //字体颜色
"padding-left:20px;" //内边距-字体缩进
"background-color: rgb(255, 255, 255);" //背景颜色
"border:2px solid rgb(20,196,188);border-radius:15px;");//边框粗细-颜色-圆角

2. PushButton部件:

设置形成的是一个浅绿色按钮,鼠标悬浮或摁下有不同颜色

1
2
3
4
ui->signup->setStyleSheet("QPushButton{font: 25 14pt '微软雅黑 Light';color: rgb(255,255,255);background-color: rgb(20,196,188);"
"border: none;border-radius:5px;}"
"QPushButton:hover{background-color: rgb(22,218,208);}"//hover
"QPushButton:pressed{background-color: rgb(17,171,164);}");//pressed

设置的是一个蓝白渐变色的按钮,鼠标悬浮有不同的颜色

1
2
3
4
5
6
7
ui->signUp->setStyleSheet("QPushButton{background-color: qlineargradient(spread:pad, x1:0.52, y1:1, x2:0.54, y2:0,"
"stop:0.0112994 rgba(64, 145, 252, 255),stop:1 rgba(255, 255, 255, 255));"
"color: rgb(255, 255, 255);"
"border:0px groove gray;border-radius:7px;padding:2px 4px;"
"font: 10pt 'Candara';}"
"QPushButton:hover{background-color: qlineargradient(spread:pad, x1:0.52, y1:1, x2:0.54, y2:0,"
"stop:0.0112994 rgba(66, 175, 255, 255),stop:1 rgba(255, 255, 255, 255))};");

设置是一个蔚蓝色的按钮,按动悬浮有不同颜色

1
2
3
4
5
6
7
ui->pushButton->setStyleSheet("QPushButton{background:qlineargradient(spread:pad,  x1:0.460227, y1:0, x2:0.465818, y2:0.875, stop:"
"0 rgba(170, 255, 255, 255), stop:1 rgba(255, 255, 255, 255));"
"border-radius:8px;"
"border:2px solid rgb(0, 170, 255);"
"color:rgb(17,17,17);}"
"QPushButton:hover{background:qlineargradient(spread:pad, x1:0.460227, y1:0, x2:0.443091, y2:0.898, stop:0 rgba(0, 255, 255, 255), stop:1 rgba(255, 255, 255, 255))}"
"QPushButton:hover:pressed{background:qlineargradient(spread:pad, x1:0.460227, y1:0, x2:0.465818, y2:0.875, stop:0 rgba(170, 255, 255, 255), stop:1 rgba(255, 255, 255, 255));}");

3. 遇到的一些问题:

  • 2023/5/23->在Qt的两个窗口头文件中都调用了相同的一个头文件,然后报了multiple definition of ~的错,分析是因为两个函数重复定义了。

    解决办法是:新建了一个.cpp文件,然后将.h文件中全部内容转到cpp文件中,然后.h文件只包含函数的定义.

  • 2023/5/24->在注册成功窗口想要直接将注册窗口和本窗口同时关闭并且转到登录窗口时遇到了问题——如何在子窗口中通过按钮将父窗口也关闭。

    解决办法是:在父窗口调用子窗口前增加一个信号槽连接,信号由子窗口.h文件中定义并在按按钮之后发出,槽函数在父窗口中声明并实现,从而实现信号通过子窗口发出并在父窗口中做出关闭操作。

    核心代码:

    1
    2
    3
    4
            SignSucess *signsucess = new SignSucess();
    connect(signsucess,&SignSucess::Close,this,&LoginWindow::Close);
    signsucess->exec();
    //Close()函数分别为子窗口和父窗口中自定义的信号和槽函数
  • 2023/5/24->在写记住密码功能时,用到QSetting库,然后通过该库与本地ini文件交互,但是把ini文件放在源代码目录下则无法保存修改,查了网上的有关说法,利用sync()函数或者重构closeEvent函数(该函数在右上角关闭窗口时自动起作用),或者在该窗口的析构函数中servalue,最终都没很好的解决我的问题。

    解决办法是:将init.ini文件放在exe程序目录下(撒花!)

    绝对路径可以这样在父类头文件窗口直接定义:

    1
    QString inipath= QCoreApplication::applicationDirPath() + "/init.ini"
  • 2023/5/24->Qt6编译生成的exe程序无法打开,显示缺少一些dll文件。

    解决办法是:打开编译器对应的命令行,这里对应的是MinGW64(已加入环境变量),先新建一个文件夹,将exe程序单独放进去,然后”cd [exe程序所在文件夹的路径]”,输入windeployqt exe文件名,例如windeployqt TeamProject.exe

  • 2023/5/24->Qt6打包生成exe文件后,打开exe程序不能连接数据库的问题。

    解决办法是:在编译器(这里对应的是MinGW64)对应的bin目录下找到libmysql.dll文件,复制到exe程序的同级目录下即可。

  • 2023/5/25->Qt6打包生成的exe文件在远端虚拟机上无法连接数据库成功的问题。

    解决办法是:在Mysql文件夹的MysqlServer文件bin中所有文件转移到exe文件同级目录下

  • 2023/5/25->Qt6打包生成的exe文件在远端虚拟机上连接上了数据库,但是远端正常机上连不上

    解决办法是:把代码中 database.setHostName("192.168.123.120");ip地址设置为无线局域网适配器 WLAN的IPv4地址(本机ip地址)。

  • 2023/6/10->QMovie播放gif时,想要使得同一个label通过按钮切换gif时出现gif暂停不切换的情况

    解决办法是:在gif切换时movie->start(),前加入movie->stop()。

  • 2023/6/11->在提升控件类时,运行出现无法找到头文件的情况

    解决办法是:在cmake.txt文件中加入 INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR})运行报错点击“忽略错误”。

  • 2023/6/11->QToolButton重写鼠标进入事件 void HallBtn::enterEvent(QEnterEvent *event)

  • 2023/6/14->连接阿里云数据库后,查询表时navicate报“lost connection …during query”错误

    解决办法是:换校园网。。

  • 2023/6/24->实现邮箱辅助账号注册时,引用QTcpSocket时报错 QTcpSocket file not found

    解决办法是:CMakeList.txt中添加

    1
    2
    3
    4
    find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Network)
    find_package(Qt${QT_VERSION_MAJOR} REQUIRED Network COMPONENTS Core)
    target_link_libraries(TeamProject PRIVATE Qt${QT_VERSION_MAJOR}::Core)
    target_link_libraries(TeamProject PRIVATE Qt6::Network)

4. Windows编程:

  • LPCVOID是一个Windows API数据类型,它是一个指向常量(只读)void的指针。在Windows API中,LPCVOID通常用于指向要读取的数据的缓冲区

  • LPVOID是一个Windows API数据类型,它是一个指向void的指针。在Windows API中,LPVOID通常用于指向要读取或写入的数据的缓冲区

  • ReadProcessMemory函数是Windows API的一部分,它允许一个进程读取另一个进程的内存区域。该函数的语法如下:

    1
    2
    3
    4
    5
    6
    7
    BOOL ReadProcessMemory(
    HANDLE hProcess,
    LPCVOID lpBaseAddress,
    LPVOID lpBuffer,
    SIZE_T nSize,
    SIZE_T *lpNumberOfBytesRead
    );

    其中,hProcess参数是要读取内存的进程的句柄,lpBaseAddress参数是要读取的内存地址(读取目标地址),lpBuffer参数是用于存储读取数据的缓冲区(保存读取结果),nSize参数是要读取的字节数,lpNumberOfBytesRead参数是指向变量的指针(没有用到则填NULL),该变量将接收实际读取的字节数。

  • WriteProcessMemory函数是Windows API的一部分,它允许一个进程向另一个进程的内存区域写入数据。该函数的语法如下:

    1
    2
    3
    4
    5
    6
    7
    BOOL WriteProcessMemory(
    HANDLE hProcess,
    LPVOID lpBaseAddress,
    LPCVOID lpBuffer,
    SIZE_T nSize,
    SIZE_T *lpNumberOfBytesWritten
    );

    其中,hProcess参数是要读取内存的进程的句柄,lpBaseAddress参数是要读取的内存地址(读取目标地址),lpBuffer参数是用于存储读取数据的缓冲区(保存读取结果),nSize参数是要读取的字节数,lpNumberOfBytesWritten参数是指向变量的指针(没有用到则填NULL),该变量将接收实际读取的字节数。

  • 获得指定进程PID的方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    DWORD MainWindow::getProcessId(const QString& processName)//获取进程PID
    {
    PROCESSENTRY32 entry;
    entry.dwSize = sizeof(PROCESSENTRY32);
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (Process32First(snapshot, &entry))
    {
    do
    {
    if (QString::fromWCharArray(entry.szExeFile) == processName)
    {
    CloseHandle(snapshot);
    return entry.th32ProcessID;
    }
    } while (Process32Next(snapshot, &entry));
    }
    CloseHandle(snapshot);
    return 0;
    }

    用法:DWORD pid=getProcessId(processname);

  • 获取进程的总基地址的方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    PVOID MainWindow::GetProcessBase(DWORD dwProcessId)
    {
    PVOID pProcessImageBase = NULL;
    //打开进程, 获取进程句柄
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
    if (NULL == hProcess)
    {
    return pProcessImageBase;
    }
    // 遍历进程模块,
    HMODULE hModule[100] = { 0 };
    DWORD dwRet = 0;
    BOOL bRet;
    bRet = EnumProcessModulesEx(hProcess, (HMODULE*)(hModule), sizeof(hModule), &dwRet, NULL);
    if (FALSE == bRet)
    {
    CloseHandle(hProcess);
    return pProcessImageBase;
    }
    // 获取第一个模块加载基址
    pProcessImageBase = hModule[0];
    // 关闭句柄
    CloseHandle(hProcess);
    return pProcessImageBase;
    }

    用法:long long baseAddress = (long long)GetProcessBase(Pid)//进程对应PID

  • 获取进程句柄:HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);


5. C++语法:

1. 虚继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include<iostream>
//虚继承:对类的继承内存存储方式进行了改变
//从原先的拷贝复制的方式变成了在子类内部空间增加了一个地址,
// 该地址指向了一些偏移量,通过指针去访问地址+偏移量
//从而锁定子类从父类那继承来的对象地址,解决了多重继承导致的父类对象重复引起子类访问时目标对象不明确的问题
class A
{
public:
int flagA;
int test;
A()
{
test = 0x666666;
flagA = 0x111111;
}
};

class B :virtual public A
{
public:
int flagB;
B()
{
flagB = 0X222222;
}
};

class C :virtual public A
{
public:
int flagC;
C()
{
flagC = 0x3333333;
}
};

class D :virtual public B,virtual public C
{
public:
int flagD;
D()
{
flagD = 0x444444;
}
};
int main()
{
B b;
C c;
D d;
d.flagA = 0x5555555;
//d.C::value = 1;
printf("%d\n", sizeof(d));
system("pause");
}

2. 友元函数

在类内声明友元函数,关键词 friend ,从而使类外定义的非成员函数可以访问该类的私有成员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include<iostream>
//友元函数
class Student
{
public:
Student(const char* name);
~Student();
private:
char name[20];
friend void printName(Student &stu);
};

Student::Student(const char* name)
{
strcpy_s(this->name, 20, name);
}

Student::~Student()
{
}

void printName(Student &stu)
{
std::cout << stu.name << std::endl;
}

int main()
{
Student stu("I am Kvancy");
printName(stu);
system("pause");
}

3. 重载运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include<iostream>
//重载运算符
using std::ostream;
class A
{
public:
A(const char* name);
~A();
void printName();
char* get_name();
friend A operator+(A& a1, A& a2);
friend ostream& operator<<(ostream& os, A& a1);
private:
char* name;

};

A::A(const char* name)
{
if (this->name = (char*)malloc(strlen(name) + 1))
{
strcpy_s(this->name, strlen(name) + 1, name);
}

}

A::~A()
{
free(this->name);
}

void A::printName()
{
std::cout << this->name << std::endl;
}
char* A::get_name()
{
return this->name;
}
A operator+(A &a1, A &a2)
{
A a3("");
char* buff = nullptr;
int len = strlen(a1.name) + strlen(a2.name);
if (buff = (char*)malloc(len + 1))
{
strcpy_s(buff, len + 1, a1.name);
strcat_s(buff, len + 1, a2.name);
}
a3.name = buff;
return a3;
}
ostream& operator<<(ostream& os, A &a1)
{
os << a1.name;
return os;
}

int main()
{
A a1("我是A1");
A a2("我是A2");
A a3 = a1 + a2;
std::cout << a3 << std::endl;
system("pause");
return 0;
}

4. 虚函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include<iostream>
//子类重写函数之后,如果定义的父类对象想调用子类重写的函数
//这个时候如果直接用父类对象的指针指向子类对象,然后调用子类重写的函数
//这个时候成功调用
//如果我们把该父类成员函数定义成虚函数,我们可以通过改变指针指向调用子类重写的函数
//编译从静态联编->动态联编
//内存中创造了虚函数表,我们可以通过父类的指针指向正确调用函数地址,从而实现调用
//virtual 关键词父类定义了子类就无需定义
//override 关键词可以避免因函数签名不一致而导致的错误,提前帮你报错显示提醒你
class Animal
{
public:
Animal();
~Animal();
virtual void make_sound () const
{
printf("Animal:make\n");
}
};

Animal::Animal()
{
}

Animal::~Animal()
{
}

class Bird:public Animal
{
public:
Bird();
~Bird();
void make_sound() const override
//如果不加override,忘写了const关键字
//编译器正常编译,父类没有成功调用子类函数,打印出"Animal:make"
{
printf("Bird:make\n");
}
};

Bird::Bird()
{
}
Bird::~Bird()
{
}
int main()
{
Animal* animal = new Animal();
Bird bird;
animal = &bird;
animal->make_sound();
system("pause");
delete animal;
return 0;
}

5. 模版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include<iostream>
//模版函数{函数模版,类模版}关键词typename或者class随意,在底层中无影响,编译器在编译的时候替换
//第一种
template<typename T>
T sum(T a, T b)
{
return a + b;
}

//第二种,参数类型不相同
template<typename T,typename T2>
void swap(T &a,T2 &b)
{
T c;
c = b;
b = a;
a = c;
}
//第三种,类模版
template<typename T>
class A
{
public:
T getValue()
{
return value;
}
void setValue(T va);

A(T value);
~A();

private:
T value;
};
//模板类是带参数的类,要求在接口实现中的类名称后面加入模板类参数,函数返回值亦如此
//格式举例如下
template<typename T>
A<T>::A(T value)
{
this->value = value;
}
template<typename T>
A<T>::~A()
{
}
template<typename T>
void A<T>::setValue(T va)
{
value = va;
}
int main()
{
char a = 1;
char b = 2;
printf("第一种:%d\n",sum(a, b));
swap(a, b);
printf("第二种:a:%d,b:%d\n", a, b);
A<int> c(1);
c.setValue(2);
printf("第三种:%d\n", c.getValue());
system("pause");
return 0;
}

6. 异常处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<iostream>
//C++异常处理机制
//throw,try,catch
//在汇编代码中没有try catch,throw函数,正常运行异常代码,然后再一个jmp指令到某一个地址(实际上catch函数)里执行相应功能
double fun(double a, int b)
{
if (b == 0)
{
throw 2;//这里throw什么类型,就是catch里面参数类型
}
return a/b;
}
int main()
{
try
{
fun(2, 0);
}
/*catch (int judge)
{
if(judge==1)
printf("异常\n");
if(judge==2)
printf("异常2\n");
}*/
catch (...)
{
printf("我是万能的!\n");
}
system("pause");
return 0;

}

perror(char*) 显示报错信息,例如 perror("wrong!:") 打印出 “wrong!:+为什么报错”


6. C++算法

1. 数组 or 容器的遍历算法 auto,for_each,transform

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include<iostream>
#include<vector>
#include <algorithm>
using namespace std;
vector<int>ve;
void visit(int out)
{
cout << out << " ";
}
//仿函数
class print2
{
public:
void operator()(int out)
{
cout << out << " ";
}
};
class trans
{
public:
int operator()(int out)
{
return ++out;
}
};
int main()
{
//遍历输出的几种方式
ve = { 0,1,2,3,4,5 };
int in[6] = { 0,1,2,3,4,5 };
//正常容器
for (auto it : in)cout << it << " ";
cout << endl;
for_each(in, in + 6, visit);
cout << endl;
//stl容器
for (auto it : ve){cout << it<<" ";}
cout << endl;
for_each(ve.begin(), ve.end(), visit);
cout << endl;
for_each(ve.begin(), ve.end(), print2());//仿函数输出结果
//transform搬运容器
cout << endl;
vector<int>ve2;
//提前分配内衬
ve2.resize(ve.size());
transform(ve.begin(), ve.end(), ve2.begin(), trans());//把ve内的值可运算性的搬运到ve2中
for (auto it : ve2)cout << it << " " ;
cout << endl;
}

2. 查找算法 find,find_if,count,count_if,binary_serach

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include<iostream>
#include<vector>
#include <algorithm>
using namespace std;
vector<int>ve;
class Person
{
public:
string name;
int age;
bool operator==(const Person& person1)
{
return person1.name == this->name && person1.age == this->age;//注意利用this指针,不能传两个参数
}
};

class equal1
{
public:
bool operator()(const Person &person1)
{
return person1.name == "p2" && person1.age == 5;
}
};
class equal2
{
public:
bool operator()(int out)
{
return out > 5;
}
};
class count_cmp
{
public:
bool operator()(int out)
{
return out > 5;
}
};
int main()
{
//常用查找算法
//find函数,在algorithm头文件中,find重心在相等
ve = { 2,3,4,5,6,7 };
auto it = find(ve.begin(), ve.end(),5);
cout << *it << endl;//返回找到的位置
Person person1 = { "p1",5 };
Person person2 = { "p2",5 };
Person person3 = { "p1",5 };
vector<Person>ve2;
ve2.push_back(person1);
ve2.push_back(person2);
ve2.push_back(person3);
auto it2 = find(ve2.begin(), ve2.end(),person2 );//要重载==运算符
cout <<it2->name << " " << it2->age << endl;
/**********************************************/
//find_if语法,find_if重心在比较
auto it3 = find_if(ve.begin(), ve.end(), equal2());//找到大于5的第一个数
cout << *it3 << endl;
auto it4 = find_if(ve2.begin(), ve2.end(), equal1());//自定义类需定义仿函数声明返回标准
cout << it4->name << " " << it4->age << endl;
/**********************************************/
//binary_search语法,重心在存在与否,使用条件是查找容器已排序,该查找效率为指数级
auto it5 = binary_search(ve.begin(), ve.end(), 7);//返回值其实是bool类型
cout << it5 << endl;
auto it6 = binary_search(ve.begin(), ve.end(), 8);
cout << it6 << endl;
/***********************************************/
//count语法,用于统计数据,返回某个元素在容器内的个数
int cnt = count(ve.begin(), ve.end(), 2);
cout << cnt << endl;
//统计类的数据时,要重载==运算符
//count_if语法,返回容器内数据条件判断后的个数
cnt = count_if(ve.begin(), ve.end(), count_cmp());
cout << cnt << endl;
//统计类的数据,要用bool型仿函数去定义比较条件
}

3. 排序算法 sort,rand_shuffle,merge,reverse

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

int main()
{
sort(ve.begin(), ve.end());//默认升序排列
sort(ve.begin(), ve.end(), greater<int>());//降序排列
sort(ve.begin(), ve.end(), cmpl);//自定义降序排列
random_shuffle(ve.begin(), ve.end());
//到此每次运行实际上结果一致,使用srand生成随机数
srand((unsigned int)time(NULL));
random_shuffle(ve.begin(), ve.end());
//结果每次运行都不同了
/**********************************/
//merge函数,使两个有序的容器合并成一个容器,并且新的容器也是有序的
merge(ve.begin(), ve.end(), ve1.begin(), ve1.end(), ve2.begin());
//ve2为新的容器
/**************************************/
//reverse函数,翻转函数
reverse(ve2.begin(), ve2.end());
/**************************************/
}

4. 拷贝替换算法 copy replace replace_if

1
2
3
4
copy(ve.begin(), ve.end(), ve2.begin());//把ve的值copy到ve2中,要提前开辟空间
replace(ve.begin(), ve.end(), 0, 5);//把ve中0替换成5
replace_if(ve.begin(), ve.end(), cmp, 5);//把ve中小于5的替换成5
swap(ve, ve2);//把ve,ve2容器中数据继续互换

5. 常用集合算法 set_intersection set_union set_difference

1
2
3
auto it2 = set_intersection(ve.begin(), ve.end(), ve2.begin(), ve2.end(), ve3.begin());//求v1,v2的交集,保存到v3,返回值为交集结束的迭代器
auto it3 = set_union(ve.begin(), ve.end(), ve2.begin(), ve2.end(), ve3.begin());//求v1,v2的并集,保存到v3,返回值为并集结束的迭代器
auto it4 = set_difference(ve.begin(), ve.end(), ve2.begin(), ve2.end(), ve3.begin());//求v1,v2的差集---属于v1,不属于v2的集合

7. 运算符优先顺序:

运算符由高到低:
第一级:圆括号 ()、下标运算符 []、结构体成员运算符 . 和 ->
第二级:逻辑非 !、按位取反 ~、自增自减 ++ 和 –、负号 -、类型转换 (类型)、指针运算符 * 和 &、长度运算符 sizeof
第三级:乘法运算符 *、/ 和 %
第四级:加法运算符 + 和 -
第五级:移位运算符 << 和 >>
第六级:关系运算符 <、<=、> 和 >=
第七级:相等运算符 == 和 !=
第八级:按位与 &
第九级:按位异或 ^
第十级:按位或
第十二级:逻辑或
第十四级:赋值运算符 =、+=、-=、*=、/=、%=、&=、^=、
第十五级:逗号运算符 ,

8. MFC

通过空项目创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//mfc.h
#include<afxwin.h>
//设置 链接器-系统-窗口
//设置 在高级里 在共享 DLL 中使用 MFC
class Myapp:public CWinApp
{
public:
virtual BOOL InitInstance();//mfc程序入口

private:

};

class MyFrame:public CFrameWnd
{
public:
MyFrame();
//~MyFrame();
afx_msg void OnLButtonDown(UINT, CPoint point);
private:

DECLARE_MESSAGE_MAP()
};

//mfc.cpp
#include"mfc.h"

Myapp app;//全局应用程序对象
//MyFrame* m_pMainwnd = new MyFrame;
BOOL Myapp::InitInstance()
{
MyFrame* frame = new MyFrame;
frame->ShowWindow(SW_SHOWNORMAL);
frame->UpdateWindow();
//保存程序指针,否则窗口一闪而过,
m_pMainWnd = frame;//m_pMainWnd线程类的一个成员

return 1;
}


BEGIN_MESSAGE_MAP(MyFrame, CFrameWnd)
ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()

MyFrame::MyFrame()
{
Create(NULL, TEXT("Crackk"));
}

VOID MyFrame::OnLButtonDown(UINT, CPoint point)
{
TCHAR buf[1024];
wsprintf(buf, TEXT("X = %d,Y = %d"), point.x, point.y);
MessageBoxW(buf);
}

通过MFC应用程序模版创建–基于对话框

在app的子类里有首界面的创建

1
2
3
4
5
6
CMFC2Dlg dlg;
m_pMainWnd = &dlg;//第一个显示的界面
//First dlg;
//m_pMainWnd = &dlg;//第一个显示的界面
INT_PTR nResponse = dlg.DoModal();
if (nResponse == IDOK)

如果要修改首界面可以添加界面类(先创建资源,再创建类)

但是新界面没有最小化和最大化和拖拽功能

如果想要在界面类里访问其他控件,例如staticText类,需要在ui界面添加变量,然后就可以通过名称来访问该控件

1
2
3
4
5
6
7
8
9
10
void CMFC2Dlg::OnBnClickedClick()
{
// TODO: 在此添加控件通知处理程序代码
static int count = 0;
count++;
if (count >= 5)
{ //hint为staticText的名称
hint.SetWindowTextW(TEXT("flag{1111}"));
}
}

这里代码块实际做的操作有两处

第一处:在父界面类的头文件中包含该控件

1
CStatic hint;

第二处:在父界面类的源文件中DoDataExchange函数里添加控件关联

1
DDX_Control(pDX, IDC_HINT, hint);//p_DX是传来的参数,后者是相关联控件id和名称

给按钮添加事件处理程序时,代码层实际修改了三处代码

所属界面类的头文件中包含该事件处理函数

1
2
afx_msg void OnBnClickedClick();
afx_msg void OnBnClickedDClick();

在源文件消息队列声明(BEGIN_MESSAGE_MAP)后添加消息声明

1
2
ON_BN_CLICKED(IDC_Click, &CMFC2Dlg::OnBnClickedClick)//id和处理函数指针
ON_BN_CLICKED(IDC_DClick, &CMFC2Dlg::OnBnClickedDClick)

在源文件中添加处理函数的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void CMFC2Dlg::OnBnClickedClick()
{
// TODO: 在此添加控件通知处理程序代码
static int count = 0;
count++;
if (count >= 5)
{
hint.SetWindowTextW(TEXT("flag{1111}"));
}
}


void CMFC2Dlg::OnBnClickedDClick()
{
// TODO: 在此添加控件通知处理程序代码
hint.SetWindowTextW(TEXT("you are so smart!!"));
}

如何格式化SetwindowTextW的参数TEXT,参数为CSting形式,等于LPCTSTR(),TEXT(),_T(),可以用Format来格式化text

1
2
3
CString text;
text.Format(_T("gogogogo!%d"), count);
hint.SetWindowTextW(text);

9. QML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
property int myvalue: 0

minimumHeight: 400
maximumHeight: 540
minimumWidth: 540
maximumWidth: 720

onWidthChanged: {
console.log("width:",width);
}
onMyvalueChanged:
{
console.log("myvalue:",myvalue);
}

Button{
id: btn1
objectName: "btn1"
x: 100
width: 50
height: 50
background: Rectangle{
border.color: btn1.focus?"blue":"black"//按钮按下获得焦点
}
Keys.onLeftPressed: {//方向键左按下
btn1.focus = false
}
}
Button{
id: btn2
objectName: "btn2"
x: 100
y: 100
width: 50
height: 50
background: Rectangle{
border.color: btn2.focus?"blue":"black"
}
Keys.onLeftPressed: {//方向键左按下
btn2.focus = true
}
}
onActiveFocusItemChanged: { //焦点发生改变时
console.log("active focus item changed:",activeFocusItem)//objectName
}


Rectangle{
x: 100
y: 100
z: 2//可以在2d中进行覆盖或者隐藏
width: 100
height: 100
color: "blue"
focus: true

MouseArea {
anchors.fill: parent
onClicked: {
console.log("on clicked")
}
}
Keys.onReturnPressed: {//控件获取键盘信号前需要获取焦点
console.log("on return pressed")
}
}


Rectangle {
id: rect1
width: 100
height: 50
color: "black"
// anchors.centerIn: parent//水平垂直居中
anchors.horizontalCenter: parent.horizontalCenter//水平居中
anchors.verticalCenter: parent.verticalCenter//垂直居中
rotation: 60 //旋转角度
scale: 2 //放缩,放大两倍
antialiasing: false //抗锯齿
border.width: 2 //边框
border.color: "red"
radius: 30 //弧度
gradient: Gradient {//渐变色 覆盖原有颜色 边框颜色不覆盖
GradientStop { position: 0.0; color: "lights teelblue" }
GradientStop { position: 1.0; color: "blue"}
}
}

Rectangle {
id: rect2
width: 100
height: 50
anchors.left: rect1.right//类似弹簧,rect1左边与rect1右边重合
anchors.leftMargin: 20//与rect1左侧相距20
anchors.top: rect1.top//y轴距离相同
color: "blue"
}
Rectangle {
id: root
width: 100; height: 100
state: "red_color" //控制状态
states: [
State {
name: "red_color"
PropertyChanges { root.color: "red" }
},
State {
name: "blue_color"
PropertyChanges { root.color: "blue" }
}
]
MouseArea {
anchors.fill: parent
onPressed: {
root.state = "blue_color"
}
onReleased: {
root.state = "red_color"

}
}
transitions: [//状态改变时进行动画,而不是瞬间完成状态改变
Transition {
from: "red_color"//状态
to: "blue_color"

ColorAnimation {
target: root
duration: 1000
}
},
Transition {
from: "blue_color"
to: "red_color"

ColorAnimation {
target: root
duration: 1000
}
}
]
}
Rectangle {
id: flashingblob
width: 100
height: 100
color: "blue"
opacity: 1.0

SequentialAnimation on color {//多段式动画

ColorAnimation {
// from: "white"
to: "red"
duration: 200
}

ColorAnimation {
// from: "white"
to: "blue"
duration: 200
}
}

MouseArea {
anchors.fill: parent
onClicked: {
animateColor.start()
animateOpacity.start()
}
}

PropertyAnimation { //属性为字符串的动画
id: animateColor;
target: flashingblob
properties: "color"
to: "green"
duration: 1000
}

NumberAnimation {//属性为数字的动画
id: animateOpacity
target: flashingblob
property: "opacity"
duration: 1000
from: 1.0
to: 0.5
}
PropertyAnimation on x {//立即触发的动画
to: 100
duration: 1000
}

}


Component { //不会立即出现的组件,需要load
id: com
Rectangle {
width: 100
height: 100
color: "blue"
Component.onCompleted: {//构造函数
console.log("Completed")
}
Component.onDestruction: {//析构函数
console.log("Destruction")
}
}
}

Component { //不会立即出现的组件,需要load
id: com2
Image {//img
id: img
source: "/login2.jpg"
}
}

Component { //不会立即出现的组件,需要load
id: com3
AnimatedImage {//gif
id: gif
source: "/GIF-1.gif"
speed: 10
}
}

Loader {//加载组件或文件
id: load
sourceComponent: com3

onStateChanged: {
console.log("status:",status)
}
}
Button {
id: button
width: 50
height: 50
x: 200
onClicked: {
load.item.paused = !load.item.paused//播放键
}
}


MouseArea {
id: mousearea
width: 100
height: 100
enabled: true //是否使能,默认为true
acceptedButtons: Qt.LeftButton | Qt.RightButton //默认只接受左键
cursorShape: Qt.CrossCursor //鼠标样式
hoverEnabled: true //默认关闭,打开可以接受悬浮信号

Rectangle {
anchors.fill: parent
color: "blue"
}
onClicked: {
console.log("clicked")
}
onHoveredChanged: {//是否悬浮
console.log("Onhoverchanged")
}

onPressed: {
var ret = pressedButtons & Qt.LeftButton
var ret2 = pressedButtons & Qt.RightButton
if(ret == Qt.LeftButton)//控制左右键不同回应
console.log("LEFT")
else
console.log("RIGHT")
console.log("pressed")
}
onReleased: {
console.log("released")
}
onPressAndHold://长摁 , 在 Press信号之后
{
console.log("hold")
}

}


Rectangle {
id: rect
width: 50
height: 50
color: "red"
opacity: (600.0 - rect.x) / 600
MouseArea {
anchors.fill: parent
drag.target: rect //加载拖动效果
drag.axis: Drag.XAxis /*| Drag.YAxis*/
drag.minimumX: 0
drag.maximumX: container.width - rect.width
// drag.filterChildren: true//子控件是否能拖动
}
}




}

Libxl使用

引入库

1
2
3
#include "libxl-3.1/libxl-3.1.0/include_cpp/libxl.h"
#pragma comment(lib,"libxl-3.1/libxl-3.1.0/lib/libxl.lib")
using namespace libxl;

读取文件

1
2
3
Book* book = xlCreateBook();
book->load("xxx.xls");
Sheet* sheet = book->getSheet(0);

读取文件大小

1
2
3
4
int rowfirst = sheet->firstRow();
int rowlast = sheet->lastRow();
int colfirst = sheet->firstCol();
int collast = sheet->lastCol();

读取文件内容(表格左上角为(0,0))

1
2
double date1 = sheet->readNum(0, 0);
const char* date2 = sheet->readStr(0, 1);

创建新sheet

1
2
Book* book1 = xlCreateBook();
Sheet* sheet1 = book1->addSheet("sheet1");

设置行宽列高

1
2
sheetM->setCol(0, 0, 20);
sheetM->setRow(0 , 20);

合并单元格

1
sheet->setMerge(0,0,1,2); // 合并第0行的1~2列

设置字体

1
2
3
4
5
6
7
8
9
Font *titleFont = bookM->addFont();
titleFont->setName("宋体");
titleFont->setSize(16);
titleFont->setBold(true);
Format* titleFormat = bookM->addFormat();
titleFormat->setAlignH(ALIGNH_CENTER);
titleFormat->setFont(titleFont);
titleFormat->setWrap(true);
titleFormat->setAlignV(ALIGNV_DISTRIBUTED);

向文件写入内容

1
2
sheet->writeStr(1,0,"xxx");
sheet->writeNum(1,1, 123);

保存结束

1
2
book->save("文件保存路径");
book->release();

JSONCPP

这篇博客概括的很全

https://www.coonote.com/cplusplus-note/jsoncpp.html