C++

C++ Bref

C++ 是一种静态类型的、编译式的、通用的、大小写敏感的、不规则的编程语言,支持过程化编程、面向对象编程和泛型编程。

C++ 被认为是一种中级语言,它综合了高级语言和低级语言的特点。

C++ 是由 Bjarne Stroustrup 于 1979 年在新泽西州美利山贝尔实验室开始设计开发的。C++ 进一步扩充和完善了 C 语言,最初命名为带类的C,后来在 1983 年更名为 C++。

C++ 是 C 的一个超集,事实上,任何合法的 C 程序都是合法的 C++ 程序。

注意:使用静态类型的编程语言是在编译时执行类型检查,而不是在运行时执行类型检查。

类 Class

类是虚拟的, 统称, 对象是类的实体

对象 Objects

objects = attributes + services = data + operations

对象 = 属性 + 服务 = 数据 + 操作

image-20220506211131674

  • Data 要避免去直接操作, 应该通过Operations去交互

三个特性

  • 封装
  • 继承
  • 多态

Objects & Class

类是虚拟的, 统称, 对象是类的实体

猫 -> 种类 -> Class

这只猫 -> 实体 -> Objects

image-20220506210930554

面向对象

C++ 完全支持面向对象的程序设计,包括面向对象开发的四大特性:

  • 封装
  • 抽象
  • 继承
  • 多态

C++ 程序可以定义为对象的集合,这些对象通过调用彼此的方法进行交互。

标准库

标准的 C++ 由三个重要部分组成:

  • 核心语言,提供了所有构件块,包括变量、数据类型和常量,等等。
  • C++ 标准库,提供了大量的函数,用于操作文件、字符串等。
  • 标准模板库(STL),提供了大量的方法,用于操作数据结构等。

hello word

Code

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>			// include io stream 后缀是不必要的是Windows的错觉
// 如果这里包含的是 iostream.h 则不再需要 using namespace std; 标准库也会有所不同

using namespace std; // Standard 标准命名空间

int main()
{
cout << "Hello world!" << endl; // c out end line
return 0;
}

编译

1
2
3
4
5
6
7
g++ -v
# 使用gcc编译
gcc main.cpp -lstdc++ -o main
# g++ 程序 g++ 是将 gcc 默认语言设为 C++ 的一个特殊的版本
g++ main.cpp -o main
# 运行它
./main

g++编译器

g++ 有些系统默认是使用 C++98,我们可以指定使用 C++11 来编译 main.cpp 文件:

1
g++ -g -Wall -std=c++11 main.cpp

g++ 常用命令选项

选项解释
-ansi只支持 ANSI 标准的 C 语法。这一选项将禁止 GNU C 的某些特色, 例如 asm 或 typeof 关键词。
-c只编译并生成目标文件。
-DMACRO以字符串”1”定义 MACRO 宏。
-DMACRO=DEFN以字符串”DEFN”定义 MACRO 宏。
-E只运行 C 预编译器。
-g生成调试信息。GNU 调试器可利用该信息。
-IDIRECTORY指定额外的头文件搜索路径DIRECTORY。
-LDIRECTORY指定额外的函数库搜索路径DIRECTORY。
-lLIBRARY连接时搜索指定的函数库LIBRARY。
-m486针对 486 进行代码优化。
-oFILE 生成指定的输出文件。用在生成可执行文件时。
-O0不进行优化处理。
-O或 -O1 优化生成代码。
-O2进一步优化。
-O3比 -O2 更进一步优化,包括 inline 函数。
-shared生成共享目标文件。通常用在建立共享库时。
-static禁止使用共享连接。
-UMACRO取消对 MACRO 宏的定义。
-w不生成任何警告信息。
-Wall生成所有警告信息。

基本语法

基本语法

基本语法和c非常类似, ; 结尾等等

三字符组(??= etc.)

一种古老的语法

三字符组就是用于表示另一个字符的三个字符序列,又称为三字符序列。三字符序列总是以两个问号开头。

三字符组替换
??=#
…..….

数据类型(bool etc.)

C++ 就是在以前的c拓展了一个 bool

C++ 为程序员提供了种类丰富的内置数据类型和用户自定义的数据类型。下表列出了七种基本的 C++ 数据类型:

类型关键字
布尔型bool
字符型char
整型int
浮点型float
双浮点型double
无类型void
宽字符型wchar_t

其实 wchar_t 是这样来的:

1
typedef short int wchar_t;

存储类(auto register etc.)

存储类定义 C++ 程序中变量/函数的范围(可见性)和生命周期。这些说明符放置在它们所修饰的类型之前。下面列出 C++ 程序中可用的存储类:

  • auto
  • register
  • static
  • extern
  • mutable
  • thread_local (C++11)

从 C++ 17 开始,auto 关键字不再是 C++ 存储类说明符,且 register 关键字被弃用。

auto 存储类

自 C++ 11 以来,auto 关键字用于两种情况:声明变量时根据初始化表达式自动推断该变量的类型、声明函数时函数返回值的占位符。

C++98标准中auto关键字用于自动变量的声明,但由于使用极少且多余,在 C++17 中已删除这一用法。

根据初始化表达式自动推断被声明的变量的类型,如:

1
2
3
4
auto f=3.14;      //double 
auto s("hello"); //const char*
auto z = new auto(9); // int*
auto x1 = 5, x2 = 5.0, x3='r';//错误,必须是初始化为同一类型

register 存储类

register 存储类用于定义存储在寄存器中而不是 RAM 中的局部变量。这意味着变量的最大尺寸等于寄存器的大小(通常是一个词),且不能对它应用一元的 ‘&’ 运算符(因为它没有内存位置)。

1
2
3
{   
register int miles;
}

寄存器只用于需要快速访问的变量,比如计数器。还应注意的是,定义 ‘register’ 并不意味着变量将被存储在寄存器中,它意味着变量可能存储在寄存器中,这取决于硬件和实现的限制。

mutable 存储类

mutable 说明符仅适用于类的对象,这将在本教程的最后进行讲解。它允许对象的成员替代常量。也就是说,mutable 成员可以通过 const 成员函数修改。

thread_local 存储类

使用 thread_local 说明符声明的变量仅可在它在其上创建的线程上访问。 变量在创建线程时创建,并在销毁线程时销毁。 每个线程都有其自己的变量副本。

thread_local 说明符可以与 static 或 extern 合并。

可以将 thread_local 仅应用于数据声明和定义,thread_local 不能用于函数声明或定义。

以下演示了可以被声明为 thread_local 的变量:

1
2
3
4
5
6
7
8
9
10
thread_local int x;  // 命名空间下的全局变量 
class X {
static thread_local std::string s; // 类的static成员变量
};
static thread_local std::string X::s; // X::s 是需要定义的
void foo() {
thread_local std::vector<int> v; // 本地变量
}


数学运算(cos sin etc.)

C++ 内置了丰富的数学函数,可对各种数字进行运算。下表列出了 C++ 中一些有用的内置的数学函数。

为了利用这些函数,您需要引用数学头文件 ****。

序号函数 & 描述
1double cos(double); 该函数返回弧度角(double 型)的余弦。
2double sin(double); 该函数返回弧度角(double 型)的正弦。
3double tan(double); 该函数返回弧度角(double 型)的正切。
4double log(double); 该函数返回参数的自然对数。
5double pow(double, double); 假设第一个参数为 x,第二个参数为 y,则该函数返回 x 的 y 次方。
6double hypot(double, double); 该函数返回两个参数的平方总和的平方根,也就是说,参数为一个直角三角形的两个直角边,函数会返回斜边的长度。
7double sqrt(double); 该函数返回参数的平方根。
8int abs(int); 该函数返回整数的绝对值。
9double fabs(double); 该函数返回任意一个浮点数的绝对值。
10double floor(double); 该函数返回一个小于或等于传入参数的最大整数。

随机数(rand etc.)

在许多情况下,需要生成随机数。关于随机数生成器,有两个相关的函数。一个是 **rand()**,该函数只返回一个伪随机数。生成随机数之前必须先调用 srand() 函数。

下面是一个关于生成随机数的简单实例。实例中使用了 time() 函数来获取系统时间的秒数,通过调用 rand() 函数来生成随机数

字符串(string etc.)

C++ 提供了以下两种类型的字符串表示形式:

  • C 风格字符串
  • C++ 引入的 string 类类型

C++ 标准库提供了 string 类类型,支持上述所有的操作,另外还增加了其他更多的功能。我们将学习 C++ 标准库中的这个类,现在让我们先来看看下面这个实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int main ()
{
string str1 = "str1";
string str2 = "str2";
string str3 = "str3";
// 无法实现 string str3 = "str3" + "str3949499"; 两个静态的string无法相加

// 字符串可以 直接相加
str3 = str1 + str2;
cout << "str3 : " << str3 << endl;
// 字符串可以 追加
str3 += str1;
cout << "str3 : " << str3 << endl;
// 从cin中直接获取
cin >> str3;
cout << "str3 : " << str3 << endl;
// 直接get到size
cout << "str3.size() : " << str3.size() << endl;
return 0;
}

基本输入输出(cin cout cerr clog)

I/O 库头文件

头文件函数和描述
该文件定义了 cin、cout、cerrclog 对象,分别对应于标准输入流、标准输出流、非缓冲标准错误流和缓冲标准错误流。
该文件通过所谓的参数化的流操纵器(比如 setwsetprecision),来声明对执行标准化 I/O 有用的服务。
该文件为用户控制的文件处理声明服务。我们将在文件和流的相关章节讨论它的细节。

标准输出流(cout)

预定义的对象 coutiostream 类的一个实例。cout 对象”连接”到标准输出设备,通常是显示屏。cout 是与流插入运算符 << 结合使用的,C++ 编译器根据要输出变量的数据类型,选择合适的流插入运算符来显示值。<< 运算符被重载来输出内置类型(整型、浮点型、double 型、字符串和指针)的数据项。

流插入运算符 << 在一个语句中可以多次使用,如上面实例中所示,endl 用于在行末添加一个换行符。

cout << str_cin << endl;

格式化输出

ostream 类的成员方法
成员函数说明
flags(fmtfl)当前格式状态全部替换为 fmtfl。注意,fmtfl 可以表示一种格式,也可以表示多种格式。
precision(n)设置输出浮点数的精度为 n。
width(w)指定输出宽度为 w 个字符。
fill(c)在指定输出宽度的情况下,输出的宽度不足时用字符 c 填充(默认情况是用空格填充)。
setf(fmtfl, mask)在当前格式的基础上,追加 fmtfl 格式,并删除 mask 格式。其中,mask 参数可以省略。
unsetf(mask)在当前格式的基础上,删除 mask 格式。
fmtfl 和 mask 参数可选值
标 志作 用
ios::boolapha把 true 和 false 输出为字符串
ios::left输出数据在本域宽范围内向左对齐
ios::right输出数据在本域宽范围内向右对齐
ios::internal数值的符号位在域宽内左对齐,数值右对齐,中间由填充字符填充
ios::dec设置整数的基数为 10
ios::oct设置整数的基数为 8
ios::hex设置整数的基数为 16
ios::showbase强制输出整数的基数(八进制数以 0 开头,十六进制数以 0x 打头)
ios::showpoint强制输出浮点数的小点和尾数 0
ios::uppercase在以科学记数法格式 E 和以十六进制输出字母时以大写表示
ios::showpos对正数显示“+”号
ios::scientific浮点数以科学记数法格式输出
ios::fixed浮点数以定点格式(小数形式)输出
ios::unitbuf每次输出之后刷新所有的流
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
using namespace std;
int main()
{
double a = 1.23;
//设定后续输出的浮点数的精度为 4
cout.precision(4);
cout <<"precision: "<< a << endl;
//设定后续以科学计数法的方式输出浮点数
cout.setf(ios::scientific);
cout <<"scientific:"<< a << endl;
return 0;
}

iomanip 格式化输出

流操纵算子作 用
*dec以十进制形式输出整数
hex以十六进制形式输出整数
oct以八进制形式输出整数
fixed以普通小数形式输出浮点数
scientific以科学计数法形式输出浮点数
left左对齐,即在宽度不足时将填充字符添加到右边
*right右对齐,即在宽度不足时将填充字符添加到左边
setbase(b)设置输出整数时的进制,b=8、10 或 16
setw(w)指定输出宽度为 w 个字符,或输入字符串时读入 w 个字符。注意,该函数所起的作用是一次性的,即只影响下一次 cout 输出。
setfill(c)在指定输出宽度的情况下,输出的宽度不足时用字符 c 填充(默认情况是用空格填充)
setprecision(n)设置输出浮点数的精度为 n。 在使用非 fixed 且非 scientific 方式输出的情况下,n 即为有效数字最多的位数,如果有效数字位数超过 n,则小数部分四舍五人,或自动变为科学计 数法输出并保留一共 n 位有效数字。 在使用 fixed 方式和 scientific 方式输出的情况下,n 是小数点后面应保留的位数。
setiosflags(mask)在当前格式状态下,追加 mask 格式,mask 参数可选择表 2 中的所有值。
resetiosflags(mask)在当前格式状态下,删除 mask 格式,mask 参数可选择表 2 中的所有值。
boolapha把 true 和 false 输出为字符串
*noboolalpha把 true 和 false 输出为 0、1
showbase输出表示数值的进制的前缀
*noshowbase不输出表示数值的进制.的前缀
showpoint总是输出小数点
*noshowpoint只有当小数部分存在时才显示小数点
showpos在非负数值中显示 +
*noshowpos在非负数值中不显示 +
uppercase十六进制数中使用 A~E。若输出前缀,则前缀输出 0X,科学计数法中输出 E
*nouppercase十六进制数中使用 a~e。若输出前缀,则前缀输出 0x,科学计数法中输出 e。
internal数值的符号(正负号)在指定宽度内左对齐,数值右对 齐,中间由填充字符填充。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
//以十六进制输出整数
cout << hex << 16 << endl;
//删除之前设定的进制格式,以默认的 10 进制输出整数
cout << resetiosflags(ios::basefield)<< 16 << endl;
double a = 123;
//以科学计数法的方式输出浮点数
cout << scientific << a << endl;
//删除之前设定的科学计数法的方法
cout << resetiosflags(ios::scientific) << a << endl;
return 0;
}

标准输入流(cin)

预定义的对象 ciniostream 类的一个实例。cin 对象附属到标准输入设备,通常是键盘。cin 是与流提取运算符 >> 结合使用的,

cin >> str_cin;

标准错误流(cerr)

预定义的对象 cerriostream 类的一个实例。cerr 对象附属到标准输出设备,通常也是显示屏,但是 cerr 对象是非缓冲的,且每个流插入到 cerr 都会立即输出。

标准日志流(clog)

预定义的对象 clogiostream 类的一个实例。clog 对象附属到标准输出设备,通常也是显示屏,但是 clog 对象是缓冲的。这意味着每个流插入到 clog 都会先存储在缓冲区,直到缓冲填满或者缓冲区刷新时才会输出。

引用& (注意区别于指针)

C++ 引用 vs 指针

引用很容易与指针混淆,它们之间有三个主要的不同:

  • 不存在空引用。引用必须连接到一块合法的内存。
  • 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
  • 引用必须在创建时被初始化。指针可以在任何时间被初始化。

引用符号:&

1
2
3
4
int i=0;
int& j=i; //引用

void Max(int& a, int& b); //引用传参

new delete 动态内存分配

1
2
3
4
int * pi = new int(225); 	//分配的同时 初始化值

int * pia = new int[10]; //数据的new和delete
delete []pia; // 带方括号释放

具体差别可以参考

[new delete malloc free]: ..\embedded!Main\嵌入式编程学习笔记.md#C类##newdeletemallocfree “new delete malloc free”

[new delete malloc free](..\embedded!Main\嵌入式编程学习笔记.md##new delete malloc free)

函数

函数参数

如果函数要使用参数,则必须声明接受参数值的变量。这些变量称为函数的形式参数

形式参数就像函数内的其他局部变量,在进入函数时被创建,退出函数时被销毁。

当调用函数时,有三种向函数传递参数的方式:

调用类型描述
传值调用该方法把参数的实际值赋值给函数的形式参数。
在这种情况下,修改函数内的形式参数对实际参数没有影响。
指针调用该方法把参数的地址赋值给形式参数。
在函数内,该地址用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。
引用调用该方法把参数的引用赋值给形式参数。
在函数内,该引用用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。

默认参数

当您定义一个函数,您可以为参数列表中后边的每一个参数指定默认值。当调用函数时,如果实际参数的值留空,则使用这个默认值。

这是通过在函数定义中使用赋值运算符来为参数赋值的。调用函数时,如果未传递参数的值,则会使用默认值,如果指定了值,则会忽略默认值,使用传递的值。

1
2
3
4
5
6
void fun(int a=1, int b=2);

void fun(int a, int b)
{
//do thing
}

Lambda函数 匿名函数

C++11 提供了对匿名函数的支持,称为 Lambda 函数(也叫 Lambda 表达式)。

Lambda 表达式把函数看作对象。Lambda 表达式可以像对象一样使用,比如可以将它们赋给变量和作为参数传递,还可以像函数一样对其求值。

Lambda 表达式本质上与函数声明非常类似。Lambda 表达式具体形式如下:

1
2
3
4
5
6
7
8
9
10
11
// 有返回值
[capture](parameters)->return-type{body}
// 无返回值
[capture](parameters){body}

// 例子
[](int x, int y){ return x < y ; }
// 如果没有参数,空的圆括号()可以省略。
[]{ ++global_x; }
// 在一个更为复杂的例子中,返回类型可以被明确的指定
[](int x, int y) -> int { int z = x + y; return z + x; }

关于capture里面的值如何获取:

[] // 沒有定义任何变量。使用未定义变量会引发错误。
[x, &y] // x以传值方式传入(默认),y以引用方式传入。
[&] // 任何被使用到的外部变量都隐式地以引用方式加以引用。
[=] // 任何被使用到的外部变量都隐式地以传值方式加以引用。
[&, x] // x显式地以传值方式加以引用。其余变量以引用方式加以引用。
[=, &z] // z显式地以引用方式加以引用。其余变量以传值方式加以引用。

  • 值捕获 与函数中的值传递类似。lambda表达式捕获的是变量的一个拷贝,因此我们如果在lambda表达式后面改变该变量值的话,不会影响捕获前的该变量值,这就是所谓的值捕获

    1
    2
    int a = 1;
    [a](){printf("%d\n", a;);}
  • 引用捕获 引用捕获和值捕获形式完全一样,只是在捕获列表中传的是变量的引用,类似于函数中的引用传递,变成下面这个样子

    1
    2
    int a = 1;
    [&a](){printf("%d\n", a;);}
  • 隐式捕获的方式,就是捕获的列表可以用=&代替,让编译器隐式的推断你使用的是哪个变量,然后这两个字符表示捕获的类型=表示值捕获,&是引用捕获;写出来之后就变成了如下的形式:

    1
    2
    int a = 1;
    [=](){printf("%d\n", a);};
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
// 捕获
int main ()
{
string str1 = "str1";
string str2 = "str2";
string str3 = "str3";

// 这是传值捕获
auto fun = [str1, str2]() {
cout << "5 str1 : " << str1 << endl;
cout << "5 str2 : " << str2 << endl;
};
cout << "1 str1 : " << str1 << endl;
cout << "1 str2 : " << str2 << endl;
str1 += str2;
str2 += str1;
fun();
cout << "2 str1 : " << str1 << endl;
cout << "2 str2 : " << str2 << endl;


return 0;
}
// 输出
1 str1 : str1
1 str2 : str2
5 str1 : str1
5 str2 : str2
2 str1 : str1str2
2 str2 : str2str1str2

// 被当成普通函数使用了
int main ()
{
string str1 = "str1";
string str2 = "str2";
string str3 = "str3";

auto stradd = [&](string& stra,string& strb) {
cout << stra << endl;
cout << strb << endl;
stra += strb;
strb += stra;
};

cout << "1 str1 : " << str1 << endl;
cout << "1 str2 : " << str2 << endl;
stradd(str1, str2);
cout << "2 str1 : " << str1 << endl;
cout << "2 str2 : " << str2 << endl;

return 0;
}
//输出
1 str1 : str1
1 str2 : str2
str1
str2
2 str1 : str1str2
2 str2 : str2str1str2
  • 这个知识点没看懂是匿了什么名, 不知所云, 难道和匿名没关系?只是捕获的功能?

函数重载

  • 确保函数名一致,在调用时根据参数来判断调用那个函数。
  • 其参数个数或类型有所不同。
1
2
3
4
5
6
int Max(int a, int b);
double Max(double a, double b);


Max(112, 223)
Max(1.2, 2.3)

类和对象

  • 对象是类的实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MyClass;		//类的声明,在被引用前声明,被其他类引用相互引用

class MyClass
{
int a; //默认私有属性,数据成员不能初始化 //int a(20);错误
public: //公有成员
int Fun(void); //这里放声明,或者直接定义在类里面(直接定义在类里面默认内联)
private: //私有成员
protected: //保护成员
};

int MyClass::Fun(void) //可以定义在类里面,也可以定义在外面
{
}

构造函数和析构函数

构造函数

  • 与类同名
  • (有但不指定)返回值
  • 可重载
  • 可以有传入参数
  • 创建对象时自动调用
  • 初始化由类中声明顺序决定,与初始化列表顺序无关
  • 初始化列表优先于构造函数内的赋值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Line
{
public:
void setLength( double len );
double getLength( void );
Line(double len); // 这是构造函数

private:
double length;
};
// 成员函数定义,包括构造函数
Line::Line( double len)
{
cout << "Object is being created, length = " << len << endl;
length = len;
}

初始化列表

使用初始化列表来初始化字段:

1
2
3
4
Line::Line( double len): length(len)
{
cout << "Object is being created, length = " << len << endl;
}

上面的语法等同于如下语法:

1
2
3
4
5
Line::Line( double len)
{
length = len;
cout << "Object is being created, length = " << len << endl;
}

假设有一个类 C,具有多个字段 X、Y、Z 等需要进行初始化,同理地,您可以使用上面的语法,只需要在不同的字段使用逗号进行分隔,如下所示:

1
2
3
4
C::C( double a, double b, double c): X(a), Y(b), Z(c)
{
....
}

析构函数

  • 类名前加 ~
  • 不能有返回值
  • 无参数,不重载
  • 销毁系统自动调用
1
2
3
4
~MyClass()
{
std::cout << "Delete MyClass:" << name << endl;
}

复制构造函数

  • 与类同名
  • 只有一个参数即对同类引用

被调用的情况

  • 用类的已知对象初始化另一个正在创建的对象
1
2
3
4
5
6
7
MyClass( const MyClass& cIn )
{
x = cIn.x;
y = cIn.y;
name = cIn.name;
std::cout << "Copy MyClass" << endl;
}

this 指针

this指针指向类对象的地址

以下两函数等价

1
2
3
4
5
6
7
8
9
10
11
int MyClass::Fun( int in )
{
x = in;
return 0;
}

int MyClass::Fun( int in )
{
this->x = in;
return 0;
}

静态成员 static

变量

所有类的对象有一个相同唯一的 数据成员 (共同点)

  • static 声明的 数据成员(初始化不加static)

  • 作用域是类范围类

  • 必须要进行初始化,文件作用域进行初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
class MyClass
{
public: //公有成员
MyClass( xxx ):xxx //构造函数
{
cont++; //静态与非静态 数据成员访问方式一致,每构造一个类就会++
}
private: //私有成员
static int cont;
}

int MyClass::cont = 0; //文件作用范围 初始化

函数

所有类的对象有一个相同唯一的 函数 (操作),该函数不能直接访问非静态成员(static 变量)。

  • static 声明的函数(类外定义不能加static)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class MyClass
{
public: //公有成员
static void Print( void );
private: //私有成员
int x, y;
static int cont;
};

void MyClass::Print( void ) //不加static
{
cout << "Print1" << cont << endl; //不能使用 this ,不能引用 x、y
}


MyClass A,B;

MyClass.Print(); //建议访问方式 (表明该成员属于类,而不是对象)
A.Print(); //效果一致不建议使用
B.Print(); //效果一致不建议使用

常成员 const

常对象

  • 不可更改
  • 定义时必须初始化
  • 只能调用 常成员函数(有const),不能调用一般的成员函数(没有const的一般函数)
1
2
3
4
<类名> const <对象名>
const <类名> <对象名>

const MyClass A(1, 2);

常数据成员

  • 只能通过构造函数成员初始化列表显式初始化
1
2
3
4
5
6
7
8
9
10
11
class MyClass
{
public: //公有成员
MyClass(int i):a(i) {}
int GetCont( void ) const;
private: //私有成员
int x, y;
const int a;
};

int MyClass::a = 9; //初始化

常成员函数

  • 声明 定义都需要const
  • 常成员函数 不能更改对象的数据成员
  • 可重载
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<返回类型> <成员函数名> (<参数表>) const;


class MyClass
{
public: //公有成员
int GetCont( void ) const;
private: //私有成员
int x, y;
int cont;
};

int MyClass::GetCont( void ) const //需要加const
{
//return cont++; //不允许更改 数据成员
return cont;
}


Lib

Note

头文件

  • 每个头文件只声明一个类
  • #ifndef 防止重复包含
  • cpp 和 h 文件应该同名

读取文件发现数据长度不对

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 方法一
InLogFile.seekg(0, ios::end);
streampos pos = InLogFile.tellg();
unsigned int length = pos;

InLogFile.seekg(0, ios::beg);
char * pBuffer = new char[length];
memset(pBuffer, 0, length);
InLogFile.read(pBuffer, length);


// 方法二
std::string strr;
{ // 读出全部文件
std::ifstream in(InFilePath);
std::ostringstream tmp;
tmp << in.rdbuf();
strr = tmp.str();
}

cout << "length" << endl;
cout << length << endl;
cout << strr.length() << endl;
1
2
12552
12352

他们的输出结果似乎不太一样, 好像是对 0D 0A 的数量计算方法不太一致导致的.

读取文件全部内容

iostream著名专家Dietmar Kuehl给出了两个读取方法

1
2
3
4
std::ifstream in("some.file");
std::isreambuf_iterator<char> begin(in);
std::isreambuf_iterator<char> end;
std::string some_str(begin, end);1234

1
2
3
4
std::ifstream in("some.file");
std::ostringstream tmp;
tmp << in.rdbuf();
std::string str = tmp.str();

C/C++调用exe文件

1
2
3
4
5
6
7
// C 此为命令行控制台方法
char* a1 = (char*)"hello";
char* a2 = (char*)"world";
char* a3 = (char*)"!";
char s[100];
sprintf_s(s,"%s %s %s %s ","./ceshi.exe",a1,a2,a3);
system(s);

C++
https://www.oikiou.top/2022/5751eea2/
作者
Oikiou
发布于
2022年5月6日
许可协议