Jack Huang's Blog


  • 首页

  • 标签

  • 归档

  • 搜索

CPlusPlus运算符重载

发表于 2021-12-22

C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。

重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。

当您调用一个重载函数或重载运算符时,编译器通过把您所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。选择最合适的重载函数或重载运算符的过程,称为重载决策。

运算符重载

您可以重定义或重载大部分 C++ 内置的运算符。这样,您就能使用自定义类型的运算符。

重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。

->重载

C++98 standard §13.5.6/1 “Class member access”:

An expression x->m is interpreted as (x.operator->())->m for a class object x of type T if T::operator-> exists and if the operator is selected at the best match function by the overload resolution mechanism (13.3).

函数重载

在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。您不能仅通过返回类型的不同来重载函数。

参考链接

  1. Is operator-> “chained” for pointers? [duplicate],by stackoverflow.

CPlusPlus迭代器

发表于 2021-12-22

iterator是不是pointer呢?要看container而定,由上可知,vector的iterator是pointer,list的iterator就不是pointer,而是object利用operator overloading使它表面上的操作像pointer而已,但並不是一個pointer。

参考链接

  1. iterator到底是不是pointer? (C/C++) (STL),by 真 OO无双.

CPlusPlus的using关键字用法

发表于 2021-12-21

C++ using关键字主要有三种用法:

  • 导入命名空间
1
2
3
4
5
// 导入整个命名空间到当前作用域
using namespace std;

// 只导入某个变量到当前作用域
using std::cout;
  • 指定别名

C++ 11 通过 using 指定别名,作用等同于 typedef,但相比 typedef,逻辑更直观,可读性更好。

1
2
typedef int T; // 用 T 代替 int
using T = int; // 用 T 代替 int
  • 在派生类中引用基类成员

using关键字可以让父类同名函数在子类中以重载方式使用。

参考链接

  1. c++11中的using关键字,by 蝶泳奈何桥.
  2. C++中using的三种用法 ,by 算法集市.

CPlusPlus的typename关键字

发表于 2021-12-21

“typename”是一个C++程序设计语言中的关键字。当用于泛型编程时是另一术语”class”的同义词。typename关键字主要功能有两项:

  • class关键字的同义词

这是一项C++编程语言的泛型编程(或曰“模板编程”)的功能,typename关键字用于引入一个模板参数。

  • 类型名指示符

显式地告诉编译器,T::bar是一个类型名。这就必须用typename关键字,而非模板类的静态变量。

参考链接

  1. typename,by wikipedia.
  2. 知无涯之C++ typename的起源与用法,by libfeihu.

CPlusPlus友元函数与友元类

发表于 2021-12-21

私有成员只能在类的成员函数内部访问,如果想在别处访问对象的私有成员,只能通过类提供的接口(成员函数)间接地进行。这固然能够带来数据隐藏的好处,利于将来程序的扩充,但也会增加程序书写的麻烦。

C++ 设计者认为, 如果有的程序员真的非常怕麻烦,就是想在类的成员函数外部直接访问对象的私有成员,那还是做一点妥协以满足他们的愿望为好,这也算是眼前利益和长远利益的折中。因此,C++ 就有了友元(friend)的概念。打个比方,这相当于是说:朋友是值得信任的,所以可以对他们公开一些自己的隐私。

友元分为两种:友元函数和友元类。

友元函数

在定义一个类的时候,可以把一些函数(包括全局函数和其他类的成员函数)声明为“友元”,这样那些函数就成为该类的友元函数,在友元函数内部就可以访问该类对象的私有成员了。

友元类

一个类 A 可以将另一个类 B 声明为自己的友元,类 B 的所有成员函数就都可以访问类 A 对象的私有成员。

参考链接

  1. C++友元函数和友元类(C++ friend)详解,by c语言中文网.

Win32消息循环及窗口创建注册示例

发表于 2021-12-19

学习Windows应用程序的创建过程对理解OSG的Win32图形上下文有帮助。

Windows应用程序的创建过程

实现窗口创建的六步骤:

  1. 创建一个窗口首先要注册一个窗口类,初始化wndclass中的各个域,设置窗口过程函数。
  2. 调用RigisterClass来注册这个窗口类。
  3. 创建窗口。CreateWindow
  4. 显示窗口。ShowWindow
  5. 刷新窗口。UpdateWindow
  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
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
// Win32GUIMsg.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "Win32GUIMsg.h"

#define MAX_LOADSTRING 100

// 全局变量:
HINSTANCE hInst; // 当前实例
WCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本
WCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名

// 此代码模块中包含的函数的前向声明:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);

// TODO: 在此处放置代码。

// 初始化全局字符串
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_WIN32GUIMSG, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);

// 执行应用程序初始化:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}

HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32GUIMSG));

MSG msg;

// 主消息循环:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

return (int) msg.wParam;
}



//
// 函数: MyRegisterClass()
//
// 目标: 注册窗口类。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32GUIMSG));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WIN32GUIMSG);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

return RegisterClassExW(&wcex);
}

//
// 函数: InitInstance(HINSTANCE, int)
//
// 目标: 保存实例句柄并创建主窗口
//
// 注释:
//
// 在此函数中,我们在全局变量中保存实例句柄并
// 创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // 将实例句柄存储在全局变量中

HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

if (!hWnd)
{
return FALSE;
}

ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

return TRUE;
}

//
// 函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 目标: 处理主窗口的消息。
//
// WM_COMMAND - 处理应用程序菜单
// WM_PAINT - 绘制主窗口
// WM_DESTROY - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// 分析菜单选择:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: 在此处添加使用 hdc 的任何绘图代码...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

// “关于”框的消息处理程序。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;

case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}

参考链接

  1. 消息循环,注册窗口,创建窗口【图解】,by hnfxs.
  2. Windows消息循环理解及窗体创建步骤,by LUCKYONE906.

CPlusPlus父类子类构造函数的初始化过程

发表于 2021-12-18

创建子类对象时,子类构造函数和父类构造函数的调用过程值得好好研究。

参考链接

  1. c++ 子类构造函数初始化及父类构造初始化,by sevencheng798.
  2. C++ 类构造函数 & 析构函数,by runoob.

JavaScript代码混淆方法

发表于 2021-12-17

JavaScript代码混淆就是将JavaScript源代码,通过一系列的转换,例如变量/函数/参数重命名、字符串删除等,转换成不可读的东西,同时还能像以前一样工作。

JavaScript Obfuscator Tool是一个免费且高效的 JavaScript 混淆器(包括对 ES2019 的部分支持)。使您的代码更难以复制并防止人们窃取您的工作。例如:

混淆前:

1
2
3
4
5
// Paste your JavaScript code here
function hi() {
console.log("Hello World!");
}
hi();

使用该工具混淆后:

1
(function(_0x70aa38,_0x6395e8){var _0x57099e=_0x192f,_0x7c1cc7=_0x70aa38();while(!![]){try{var _0x56bcff=-parseInt(_0x57099e(0xf0))/0x1*(-parseInt(_0x57099e(0xee))/0x2)+-parseInt(_0x57099e(0xef))/0x3+parseInt(_0x57099e(0xeb))/0x4+parseInt(_0x57099e(0xf3))/0x5+-parseInt(_0x57099e(0xf2))/0x6+-parseInt(_0x57099e(0xf4))/0x7*(-parseInt(_0x57099e(0xea))/0x8)+parseInt(_0x57099e(0xed))/0x9*(-parseInt(_0x57099e(0xf1))/0xa);if(_0x56bcff===_0x6395e8)break;else _0x7c1cc7['push'](_0x7c1cc7['shift']());}catch(_0x5a9257){_0x7c1cc7['push'](_0x7c1cc7['shift']());}}}(_0x4312,0xd7ab0));function _0x192f(_0x596bfb,_0x95be29){var _0x43126e=_0x4312();return _0x192f=function(_0x192fed,_0x3ed7b3){_0x192fed=_0x192fed-0xe9;var _0x49c785=_0x43126e[_0x192fed];return _0x49c785;},_0x192f(_0x596bfb,_0x95be29);}function hi(){var _0x445057=_0x192f;console[_0x445057(0xec)](_0x445057(0xe9));}function _0x4312(){var _0x4f3249=['Hello\x20World!','9485888XtUGcp','2200444wypUiR','log','99CDZgzo','29822AbjrMy','403245avFbPY','43uwDKOW','2388280NXrOlo','134622vvoFuf','6451580kiRbTs','7mxMQdg'];_0x4312=function(){return _0x4f3249;};return _0x4312();}hi();

打开Chrome浏览器控制台,将混淆后的代码粘贴并运行,会发现结果是一样的。

参考链接

  1. JavaScript Obfuscator Tool,by obfuscator.

Matlab浮点数比较方法

发表于 2021-12-17

Matlab中的浮点数按照IEEE754约定,以有限的精度进行存储。因此,在进行浮点数的比较时,要特别小心,防止看不见的误差导致错误的结果。例如在Matlab中输入如下代码:

1
2
testNum=0:0.1:1
testNum(4) == 0.3 % 结果将表示两者不相等

最好采用如下方式比较两个浮点数是否相等:

1
abs(testNum(4)-0.3)<eps

参考链接

  1. While comparing the equality of two floating numbers(a,b), we use abs(a – b) < tolerance. Could anyone let me know if there’s anyway that this function may yield bad results or errors ?,by mathworks.

CPlusPlus静态变量

发表于 2021-12-14 | 更新于 2024-04-25

static 是 C/C++ 中很常用的修饰符,它被用来控制变量的存储方式和可见性。

我们知道在函数内部定义的变量,当程序执行到它的定义处时,编译器为它在栈上分配空间,函数在栈上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题: 如果想将函数中此变量的值保存至下一次调用时,如何实现? 最容易想到的方法是定义为全局的变量,但定义一个全局变量有许多缺点,最明显的缺点是破坏了此变量的访问范围(使得在此函数中定义的变量,不仅仅只受此函数控制)。static 关键字则可以很好的解决这个问题。

另外,在 C++ 中,需要一个数据对象为整个类而非某个对象服务,同时又力求不破坏类的封装性,即要求此成员隐藏在类的内部,对外不可见时,可将其定义为静态数据。

c++类静态成员函数调用成员变量

方法一

一种最简单的方法就是在类静态函数的形参列表里面加入类指针,到时候直接传入实例的this指针就能操作类成员变量了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class A
{
public:
static void test(A *a)
{
a->m_a += 1;
}
void hello()
{
}
private:
static int m_staticA;
int m_a
};

方法二

一开始定义的时候就把实例的this指针复制给一个静态的类指针,这样不用传入this指针直接操作,但是这样如果多个实例都需要操作的时候会出现问题,定义多个变量的时候需要注意静态指针指向的是哪个实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class A
{
public:
A()
{

}
static void test()
{
m_gA.m_a += 1;
}
void hello()
{
}
private:
static int m_staticA;
static A *m_gA;
int m_a
};

A* A::m_gA=NULL;

参考链接

  1. C/C++ 中 static 的用法全局变量与局部变量,by runoob.
  2. C/C++ 中的static关键字,by Arkin.
  3. c++类静态成员函数调用成员变量,by xxwtiancai.
  4. C++类里面定义一个指向自己的静态成员函数,by JJ_S.
上一页1…202122…54下一页

Jack Huang

535 日志
69 标签
© 2026 Jack Huang
由 Hexo 强力驱动
|
主题 — NexT.Muse