Marco Nie - c++
type: channel
link: https://blog.niekun.net/category/cpp/
items: Qt 项目图片压缩库环境配置教程
items: QT 中通过 QCustomPlot widget 绘制可视化曲线表
items: c++ 类型转换
items: c++ 字符串数组指针的研究
items: Macros 聚集 in c++
items: c++ 中 string 字符串的含义
items: c++ 中数组类型数据作为 function 参数时的注意事项
items: C++ 入门教程之八 -- Templates - Exceptions - Files
items: C++ 入门教程之七 -- 继承和多态
items: C++ 入门教程之六 -- Classes 实践/头文件/操作符复用

Qt 项目图片压缩库环境配置教程
type: item
date: 2026-03-28T08:02:47+00:00
description: 适用平台：Windows (MinGW) / macOS (Apple Silicon)涉及库：libpng · zlib · libimagequant用途：Qt 项目中对 PNG 进行缩放后有损压缩，效果接近 tinypng一、原理说明库作用zlib通用压缩库，libpng 的底层依赖libpngPNG 编码/解码，负责将量化后的调色板写入 PNG 文件libimagequant核心量化算法，将 RGBA 图像减色为 256 色调色板（与 tinypng 同类算法）二、Windows (MinGW) 配置2.1 前置要求Qt（含 MinGW 工具链，如 mingw1310_64）CMake 3.16+（https://cmake.org/download/）Git确保 MinGW 在 PATH 中，在 cmd 执行：set PATH=C:\Qt\Tools\mingw1310_64\bin;%PATH%⚠️ 重要：后续所有编译步骤必须在无空格路径下进行。如果你的用户目录包含空格（如 C:\Users\Marco Nie），请在 C:\ 根目录下建立工作目录。mkdir C:\build_libs cd C:\build_libs2.2 编译 zlibcd C:\build_libs git clone https://github.com/madler/zlib.git --branch v1.3.1 --depth 1 cd zlib cmake -B build -G "MinGW Makefiles" ^ -DCMAKE_BUILD_TYPE=Release ^ -DBUILD_SHARED_LIBS=OFF ^ -DCMAKE_INSTALL_PREFIX=C:/build_libs/third_party/zlib cmake --build build cmake --install build cd ..安装结果：C:\build_libs\third_party\zlib\ include\ ← zlib.h, zconf.h lib\ ← libzlibstatic.a2.3 编译 libpngcd C:\build_libs git clone https://github.com/pnggroup/libpng.git --branch v1.6.43 --depth 1 cd libpng cmake -B build -G "MinGW Makefiles" ^ -DCMAKE_BUILD_TYPE=Release ^ -DPNG_SHARED=OFF ^ -DPNG_STATIC=ON ^ -DPNG_TESTS=OFF ^ -DZLIB_ROOT=C:/build_libs/third_party/zlib ^ -DCMAKE_INSTALL_PREFIX=C:/build_libs/third_party/libpng cmake --build build cmake --install build cd ..安装结果：C:\build_libs\third_party\libpng\ include\ ← png.h, pngconf.h, pnglibconf.h lib\ ← libpng16.a2.4 编译 libimagequantlibimagequant 2.17+ 已用 Rust 重写，MinGW 下需使用最后一个纯 C 版本 2.12.6，该版本没有 CMakeLists.txt，直接用 gcc 手动编译。cd C:\build_libs git clone https://github.com/ImageOptim/libimagequant.git ^ --branch 2.12.6 --depth 1 libimagequant_c cd libimagequant_c :: 编译所有源文件 gcc -c -O3 -std=c99 -ffast-math ^ libimagequant.c blur.c kmeans.c mediancut.c mempool.c nearest.c pam.c :: 打包静态库 ar rcs libimagequant.a ^ libimagequant.o blur.o kmeans.o mediancut.o mempool.o nearest.o pam.o :: 手动安装 mkdir C:\build_libs\third_party\libimagequant\include mkdir C:\build_libs\third_party\libimagequant\lib copy libimagequant.h C:…

QT 中通过 QCustomPlot widget 绘制可视化曲线表
type: item
date: 2021-03-19T09:24:46+00:00
description: 今天在项目中需要添加一个柱状图，但由于我们的项目是 QT 4.8 的所以不支持 QtCharts。查询了下发现有 QCustomPlot 可以完美的实现需求，使用方法也很简单。官网：https://www.qcustomplot.com/下载：https://www.qcustomplot.com/index.php/downloadQCustomPlot 只有两个文件 qcustomplot.cpp 和 qcustomplot.h，将其复制到项目目录中并添加到项目中。然后引用头文件即可：#include "qcustomplot.h" 我们需要在 ui 中添加一个 widget 然后右键点击控件，选择提升：提升的 class 名称修改为 QCustomPlot：点击 add 然后点击 promote 即可。编译后可以看到图表样式：在使用中如果需要根据数据变化刷新渲染的图形，记得在修改数据后调用

c++ 类型转换
type: item
date: 2021-01-14T03:58:00+00:00
description: Implicit conversion 隐式转换当一个数据复制为兼容格式的类型时，隐式转换可以自动完成。请看下面示例：double a = 100.1; int b; b = a; cout << b << endl; //output: //100以上示例中，我们将 double 类型的数据复制给 int 类型的变量，不会引起语法报错，这就是 Implicit 隐式类型转换，也叫 standard conversion 标准转换。标准转换对一些基本的数据类型有效，能够对一些 numerical 数值类型的数据间进行转换，如：double to int，int to float，short to double，int to bool 等，也可以在 pointer 指针类型间转换。从小一些的整型如 short 转换到 int 类型，或者从 float 类型转换到 double 类型，这种转换过程叫做 promotion 晋升操作。这种转换可以确保原始数据完整的复制到目标数据类型中。其他数学运算类型间的转换可能不一定会完整的保留原始数据，下面是几种情况举例：一个负整数转换为 unsigned 类型，结果为 unsigned 类型数据所能表达的最大值数据转换为 bool 类型的数据时，对于数值类型原始数据为 0 时，对于指针类型指针数据为 null pointer 时，对应转换为 false。原始数据为所有其他情况时，转换结果为 true。浮点型数据转换为整型数据，数据会被截取整数部分，如果数据结果超出目标数据类型所能表达的最大值，会得到 undefined我们可以看到，隐式转换可能会带来数据精度的丢失，编译器此时会提示一条 warning 警告。可以通过使用 explicit conversion 显式转换来避免警告信息。class 的隐式转换class 中的隐式转换通过以下三个 function 控制：单参数的 constructors 允许从一个特定类型的数据隐式转换构造为一个 object通过等号操作符 Assignment operator 复用来隐式转换类型传播符 Type-cast 来隐式转换为特定的类型下面示例解释各种方式的含义：class A {}; class B { public: B(A a) {} //constructor: conversion from A B operator=(A a) {return *this;} // assignment operator: conversion from A operator A() {return A();} // type-cast: conversion to A }; int main() { A a; // instance a B b = a; // constructor b from a B c(a); // constructor c from a b = a; // assignment a to b a = b; // convert b to A type and assignment to a return 0; }以上实例分别介绍了三种隐式转换的方式。构造器的一个传入参数为 A 类型数据，也就是等同于可以将 A 类型因素转换为 B 类型通过操作符复用将等号= 重新定义，等号右边的为 A 类型数据时，以A类型数据作为构造器参数返回 B 类型 object 指针当执行 B 类型数据赋值给 A 类型时，会通过类型传播符定义的 function 返回 A 类型 object构造器初始化 object时，当只有一个参数时，就相当于把传入数据转换为对应 object 类型了。上面示例中可以看到，有两种方法来构造 object：B b = a; // constructor b from a B c(a); // constructor c from a以上两种方式都是将 a 作为初始化参数构造 B 类型的 object。编写了等号操作符复用后，对某个指定类型的外部 object 进行等号操作时就会将其转换为当前 object 类型，而不会报错。通过类型传播符可以将 object 转换为其他指定类型的 object。关于操作符复用的语法参考我之前的教程：https://blog.niekun.net/archives/1920.htmlexplicit 关键词当调用一个 function 时，对于其传递参数 c++ 允许进行隐式转换，这在一些情况下会引起一些问题，因为我们并不是所有情况下都希望自动进行转换的。在以上示例中加入 function：void function(B b) {} 此 function 有一个 B 类型的参数，但是在实际…

c++ 字符串数组指针的研究
type: item
date: 2020-12-08T13:37:00+00:00
description: 在实际使用中发现对字符串的运用是一个容易混乱的地方，尤其是使用指针指向一个字符串数组的时候。下面做一些简单分析。一个简单的测试： const char* test1 = "abc"; const string test2 = "abc"; cout << test1 << endl; cout << *test1 << endl; cout << test2 << endl; cout << sizeof (test1) << endl; cout << sizeof (test2) << endl;输出如下：abc a abc 8 24以前我的教程里提到过，字符串就相当于一个字符数组。指针会指向它的首个字符地址。test1 指针理论上存储着字符串的首地址。但我们可以看到直接输出 test1 会得到实际字符串内容，而不是首个字符地址。输出 *test 会得到正常的首字符内容。字符串指针使用 sizeof 得到这个指针所占用内存大小，而不是字符串内容的大小。同时我们可以发现，一个字符指针可以直接指向一个字符串，而不需要先定义一个字符串变量然后建立指针指向这个变量。这是因为一个字符串可以看做一个字符数组，同时它也是一个整体，字符指针可以直接定义指向它。下面测试 int 型数组： const int test3[] = {1, 3 ,5}; const int* test4 = test3; cout << test3 << endl; cout << test4 << endl; cout << test4[0] << endl; cout << *test4 << endl; cout << sizeof(test4) << endl; cout << sizeof(test4[0]) << endl;输出结果：0x7ffee8cbaa58 0x7ffee8cbaa58 1 1 8 4可以看到直接输出数组名称或指针名称得到的是数组所在地址。*test 和 test[0] 会得到数组第一位内容。test4 是一个指针，所以 sizeof 得到的是这个指针做占用的内存空间而不是数组本身占用空间。无法通过 sizeof 计算出数组个数。以上实验，我们先建立了一个 int 型数组变量，然后建立 int 型指针指向这个变量，如果直接在一行中建立一个指针指向一个数组会报错，这就和上面测试的字符指针不一样了。因为其他类型的数组不同于字符串，它的每个元素是独立的个体，所以无法使用一个指针直接指向他们全部。下面做最后一个测试：const char* test5[] = { "abc", "def", "ohg", "asdf" }; const string test6[] = { "abc", "def", "ohg", "asdf" }; int x = sizeof (test5)/sizeof(test5[0]); cout << test5 << endl; cout << *test5 << endl; cout << test5[0] << endl; cout << *test5[0] << endl; cout << x << endl; cout << sizeof(test5) << endl; cout << sizeof(test5[0]) << endl; cout << "*************\n"; x = sizeof (test6)/sizeof(test6[0]); cout << test6 << endl; cout << *test6 << endl; cout << test6[0] << endl; cout << x << endl; cout << sizeof(test6) << endl; cout << sizeof(test6[0]) << endl;输出结果如下：0x7ffee596ea40 abc abc a 4 32 8 ************* 0x7ffee596e9e0 abc abc 4 96 24由于字符串本身就是一个字符数组，所以一个字符串数组相当于一个二维的数组。定义字符串数组的指针，就是数组中每个字符串对应的指针的集合。所以这个数组指针本身不是字符串类型的，而它的每个指针元素都是字符串指针类型的。可以看到类似于第一组测试，非字符串的指针直接输出指针名称，所以 test5 得到字符串数组的地址。*test5 和 test5[0] 都表示指针数组第一个元素，也就是字符串类型的指针，根据第一组实验可以知道使用字符串指针名称输出本身字符串而不是地址，所以输出此指针可以直接得到字符串内容。*test5[0] 就是字符串指针的首字符地址内容，也就是得到第一个字符串第一个…

Macros 聚集 in c++
type: item
date: 2020-12-01T03:37:00+00:00
description: 在 c++ 中，一个 Macro 就是一段代码的聚合。使用这个 macro 名称就代表着对应的代码段。有两种常见的 macro：object 形式，function 形式。可以定义任意有效的字符作为 macro 名称，甚至是 c 关键词。object 形式object 形式的 macro 就是简单的使用一个 identifier 代替代码片段。使用 #define 定义一个 macro：#define TESTINT 1024 void main() { int a = TESTINT; cout << a << endl; } //output: //1024也可以定义一个片段：#define NUMBERS 1, 2, 3 void main() { int x[] = { NUMBERS }; //int x[] = { 1, 2, 3 };这两句效果相同 }也可以多层定义：#define NUMBER1 1 #define NUMBER2 NUMBER1以上示例中 NUMBER2 等于 NUMBER1。function 形式可以定义 function 形式的 macro，需要在定义中 macro 名称后加上圆括号()。例如：#define lang_init() c_init()定义后就可以使用 lang_init() 来调用 c_init() 了，类似于 alias。object 类型的 macro 可以和 function 类型的 macro 同名，区别就是有没有圆括号：#define test 100 #define test() func() void main() { int a = test; test(); }以上就是对 macro 的简单介绍。参考链接：https://gcc.gnu.org/onlinedocs/cpp/Macros.html

c++ 中 string 字符串的含义
type: item
date: 2020-11-25T03:52:00+00:00
description: 有如下代码：int main() { char *s; s = "hello"; cout << *s << endl; cout << s << endl; return 0; } //OUTPUT: //h //hello首先定义了一个指针，然后给指针赋值为一个字符串。看起来以上写法有错误，s 指针是一个地址，为什么给它赋值一个字符串？因为在 c++ 中字符串类似于我们提到的数组，使用数组名就表示第一个数组元素的地址。例如：int main() { int arr[] = {1, 3}; int *p = arr; cout << *p << endl; cout << *(p+1) << endl; return 0; } //OUTPUT: //1 //3同样在字符串中，s = "hello" 表示将首字母 h 的地址赋给指针。

c++ 中数组类型数据作为 function 参数时的注意事项
type: item
date: 2020-11-25T03:16:00+00:00
description: 关于 function 的基础教程参考：C++ 入门教程之四 -- Functions当 function 的传入参数为数组时，如果我们想要得到数组元素个数可能会这样写：void testFunc(int arr[]) { int count = sizeof(arr)/sizeof(arr[0]); } int main() { int arr[] = {1, 3, 6, 8}; cout << testFunc(arr) << endl; return 0; }sizeof function 可以返回数据占用内存空间的大小。所以用整个 arr 大小除以第一个元素大小可以得到数组元素个数。但是测试会发现以上得到的 count 值并不是 arr 数组元素个数 4 而是 2。这是因为当 function 传入数组数据时，会自动将其转换为 pointer 指针类型。这时候使用 sizeof() 得到的不是 arr 数据所在地址的内存大小，而是这个指向 arr 数组的指针所占用内存大小。我们做个实验：int main() { int *arrP = new int[4]; cout << sizeof(arrP) << endl; cout << sizeof(arrP[0]) << endl; return 0; } //output: //8 //4以上建立了一个指针指向 4 个元素的数组，然后分别查看其整个指针和某个元素指针的内存大小，得到的结果是 8 和 4。所以他们两个相除结果为 2。因为指针指向的是数组第一个元素，如果我们要通过指针给数组元素赋值，可以使用 *(pointer + n) 的方式完成，例如：int *arrP = new int[4]; *arrP = 1; *(arrP+1) = 2;*(arrP+1) 就是第 2 个数组元素。可以用指针查询数组中某个元素的内存大小，数组名 arr 表示数组所在地址(不需要加地址转换符&)：int main() { int arr[] = {1, 3, 6, 8}; int *arrP = arr; cout << sizeof(*arrP) << endl; cout << sizeof(*(arrP+1)) << endl; return 0; } //output: //4 //4由于 arr 数组名表示此数组第一个元素所在地址的指针，所以我们可以直接使用此名称来用指针的方式地区元素数据：int main() { int arr[] = {1, 3, 6, 8}; cout << *arr << endl; cout << *(arr+1) << endl; return 0; } //output: //1 //3那么如何在 function 使用数组作为传入数据时如何能够直接使用它的数据而不是指针类型呢？可以使用以下方法：template <size_t N> int testFunc(int (&arr)[N]) { int count = sizeof(arr) / sizeof(arr[0]); return count; } int main() { int arr[] = {1, 3, 6, 8}; int count = testFunc(arr); cout << count << endl; return 0; } //OUTPUT: //4创建一个 function template，size_t 类型表示任意数据类型的元素占用内存大小，此处将其作为 generic data type 用来定义实际传入的数组所占用内存容量的 template，然后以传入数据的实际地址的模式将数组的元素都顺序都传入 function。这样传入数据就是实际数据地址而不是指针。关于 function 的传入数据实际地址是使用指针形式 * 还是 & 形式，在前面我介绍过，形式如下：void test1(int *a) { *a = 3; } void test2(int &a) { a = 2; } int main() { int a = 1; int *p = &a; test1(p); cout << a << endl; test2(a); cout << a << endl; return 0; } //OUTPUT: //3 //2function 中使用在指针类型的传入数据时需要传入一个指针，当定义为 & 时可以直接传入数据名称。两种方法都是 by reference 会影响到对应内存地址的数据内容。可参考教程：C++ 入门教程之四 -- Functions参考链接：https://stackoverflow.com/questions/4839626/…

C++ 入门教程之八 -- Templates - Exceptions - Files
type: item
date: 2020-11-23T13:41:00+00:00
description: function template使用 function 和 class 使我们编程更加简单及易操作。但是它们仍然受限于 c++ 编程规范，在定义它们的参数时必须指定参数的类型。例如：int sum(int a, int b) { return a+b; } int main () { int x=7, y=15; cout << sum(x, y) << endl; }以上示例中，需要我们定义sum function 需要传入两个 int 型数据，返回其相加结果。在 main 中调用 sum function。sum() 可以正确的执行指令，但它的限制是必须传入 int 类型的数据。如果需要实现两个 double 类型数据相加，需要再次定义新 funtion：double sum(double a, double b) { return a+b; }使用 function template 能够让我们只定义一个 sum() 来适用于所有类型的数据。使用关键词 template 来定义一个 function template，在尖括号<>内定义通用数据类型：template <class T> 关键词 class 表示一个申明要定义 generic 通用数据类型，注意不要和我之前学习的 class 混淆。也可以使用关键词 typename：template <typename T> T 表示我们的 generic 通用数据类型名称，在后续中可以使用此名称代表数据类型，可以是任意自定义字符。修改我们的示例：#include <iostream> using namespace std; template <class T> T sum(T a, T b) { return a + b; } int main() { int x=7, y=15; cout << sum(x, y) << endl; double a=7.15, b=15.54; cout << sum(a, b) << endl; return 0; }我们在 function 中建立了一个 generic data type 通用数据类型 T，返回值和传入参数类型都为 T。在 mian 中调用时，会根据实际传入数据类型来动态确定 T 的实际类型。function template 可以节省编程中很多时间，因为只需要一次定义就可以兼容不同的数据类型。我们也可以同时定义多个 generic data type，使用逗号, 分隔多个定义类型：template <class T, class U> T smaller(T a, U b) { return (a < b ? a : b); } int main () { int x=72; double y=15.34; cout << smaller(x, y) << endl; }以上示例定义了两个通用数据类型，返回值类型为第一种数据类型。(a < b ? a : b) 表达式的意思是：判断 a 是否小于 b，如果结果为 true 则返回 a 的值，如果结果为 flase 返回 b 的值，两个参数可以是不同数据类型，如：int 和 double。在 mian 中调用 smaller function，返回结果为两个参数中较大的那个的值，由于返回值类型为第一个定义数据类型 T，而我们调用时传入的第一个参数类型为 int，所以返回结果也为 int 型。需要注意的是在一旦定义了 function template，在 function 中就一定要使用定义的那些通用数据类型，否则编译器会报错。class template同样也可以定义 class template，允许 class 的元素类型为 generic data type。语法如下：template <class T> class MyClass { };类似于 function template，多个 generic data type 使用逗号, 分隔：template <class T,class U> 下面举例说明使用方法：template <class T> class Pair { public: Pair (T a, T b): first(a), second(b) { } private: T first, second; };以上建立了一个 class template，类型为 T，通过构造器对 private 里的两个 T 类型的参数初始化数据。在 class template 外定义 function，如 class 大括号外或一个单独文件，需要在 class 后标记 class template 内定义过的 generic type。例如…

C++ 入门教程之七 -- 继承和多态
type: item
date: 2020-11-21T14:31:00+00:00
description: inheritance 继承inheritance 继承是面向对象编程最重要的概念之一。继承允许我们基于已有的 class 创建新的 class。这能够极大的方便我们创建应用程序。一个 class 的属性被其他 class 继承，我们称这个 class 叫做 base class。一个从 base class 继承属性的 class 我们称其为 derived class。一个 derived class 获得所有 base class 的功能，且可以有自己独有的功能：继承的概念是 is a 属于是什么 的关系，例如：猫 is a 动物，狗 is a 动物。两者都继承了动物的属性。我们来建立两个 class：Mother 和 Daughter：class Mother { public: Mother() {}; void sayHi() { cout << "Hi"; } }; class Daughter { public: Daughter() {}; };Mother 有一个 sayHi() function。下面我们让 Daughter 继承 Mother 的属性，Daughter class 名称修改如下：class Daughter : public Mother { public: Daughter() {}; };使用一个冒号: 标记 base class。access specifier 访问标记符 public 表示所有 base class 里 public 段下的内容继承给 derived class 里的 public 段下。以上示例中 Daughter 继承了所有 Mother 的 public 下的元素，所以我们可以实例化一个 Daughter 的 object 然后调用 sayHi() function 了：#include <iostream> using namespace std; class Mother { public: Mother() {}; void sayHi() { cout << "Hi" << endl; } }; class Daughter: public Mother { public: Daughter() {}; }; int main(int argc, const char * argv[]) { Daughter d; d.sayHi(); return 0; }关于 access 访问标记符的使用，在下面会详细介绍使用方法。一个 derived class 可以继承所有 base class 的 function 出过一下几种特殊情况类型：constructor and destructor 构造器和销毁器复用操作符 functionfriend function一个 class 可以同时继承多个 base class，使用逗号, 分隔 base class，如：class Daughter: public Mother, public Father。protected 元素对于 class 中的元素的 access 访问表示符，我们前面使用了 public 和 private。public 里的元素可以被外界访问或修改，private 里的元素只能被 class 内部使用，或者通过 friend function 来读取。除了以上两种识别符外，还有一种类型：protected。在 protected 内的元素和 private 段内的很类似。唯一的区别是，protected 内的元素可以被 derived class 访问。例如我们给 Mother 添加一个 protected 元素：class Mother { public: void sayHi() { cout << var; } private: int var=0; protected: int someVar; };someVar 变量可以被 Daughter 访问。继承的类型access 访问标记符能够用来定义继承类型。在上面的示例中我们使用 public 作为访问标记符：class Daughter: public Mother。private 和 protected 同样可以被使用。三者的区别：Public Inheritance: base class 里 public 段内的元素继承到 derived class 里的 public 段内，base class 里 protected 段内的元素继承到 derived class 里 protected 段内，base class 里 private 段内的元素永远不能能够被 derived class 直接访问，但可以通过 …

C++ 入门教程之六 -- Classes 实践/头文件/操作符复用
type: item
date: 2020-11-21T08:42:00+00:00
description: 下面我们通过实际应用来介绍如果在真实环境下应用。我们使用 Code::Blocks IDE 来进行调试。这是一个免费的 c++ 开发环境，能够应用于绝大多数使用场景。官网：http://www.codeblocks.org/在下载界面下载对应系统版本的安装包：http://www.codeblocks.org/downloads/26最好安装带编译器的版本，这样就可以直接使用。新建项目安装好 codeblock 后新建一个项目：选择 console application：根据提示设置项目名称等，完成项目建立。然后添加一个 class：设置 class 名称，取消勾选 has destructor，勾选 headers and implementation file shall be in same folder：完成后项目结构如下：main.cpp 项目主文件MyClass.cpp class source 源文件MyClass.h class header 头文件头文件和源文件头文件 .h 申明了 class 的 function 和 variable 变量等元素，我们新建的 class 头文件内容如下：#ifndef MYCLASS_H #define MYCLASS_H class MyClass { public: MyClass(); protected: private: }; #endif // MYCLASS_H里面只默认包含了一个 constructor 构造器 MyClass()。源文件 .cpp 包含了这个 class 具体 function 和 variable 等元素的实现过程。当前只有一个空的构造器 function：#include "myclass.h" MyClass::MyClass() { //ctor }范围解析符：我们注意到源文件内构造器前的两个冒号::，叫做 scope resolution operator 范围解析符。这个符号是用来表示那些已经在头文件内申明过的 function 要在这里做具体实现了。用来和头文件内定义的元素进行关联的作用。关于::和.的使用场景我的理解是，当在定义一个元素或功能时用范围解析符::，当实例化object后使用其一个元素或功能时用点.，例如：//定义一个元素为class内的一个att1类型： MyClass1::att1 a; //使用class的function： MyClass2 obj; obj.func();要在 main 总使用我们创建的 class，只需要在其中引用头文件名即可:#include <iostream> #include "myclass.h" using namespace std; int main() { MyClass obj; return 0; }总体来说，头文件用来定义 class 提供了哪些功能及元素，源文件用来具体实现这些功能。destructor 销毁器和上一章我们讲到的 constructor 构造器类似，destructor 销毁器也是一个特殊的 function，他在 object 被销毁时自动执行。销毁一个 object 一般是在跳出创建这个 object 的 scope 段或者使用 pointer 指针指向这个 object，使用 delete 指令清除此指针指向的数据。销毁其的写法和构造器类似，使用 class 名作为 function 名字，前面加上一个波浪符~。当然也是没有返回值类型的。例如：class MyClass { public: ~MyClass() { // some code } };使用销毁器能够方便的实现在关闭程序时释放资源，关闭文件，释放内存等功能。在头文件中声明一个销毁器：class MyClass { public: MyClass(); ~MyClass(); };然后再源文件内定义具体实现内容：#include "MyClass.h" #include <iostream> using namespace std; MyClass::MyClass() { cout<<"Constructor"<<endl; } MyClass::~MyClass() { cout<<"Destructor"<<endl; }不同于构造器，销毁器不能使用参数，也不能被重写，也就是一个 class 只能有一个销毁器。销毁器不是必须有的，不需要的话可以不写返回我们的 main，我们已经定义了一个 object MyClass obj，编译运行程序，会在终端输出以下：Constructor Destructor选择符使用选择符 -> 可以访问一个指针指向的 object 的元素。…