初学C++做的笔记

C++开发环境

  • CLion,收费的
  • VS2017,推荐使用社区版(免费的)

Python和C++的区别

  • Python属于解释性语言,看到一行执行一行。
  • C++属于编译性语言,写了代码之后,不会直接对代码直接执行,会先转成一种中间语言(可能是汇编语言,也可能是机器语言),再把中间性语言放到机器里去执行。
  • 编译性语言和解释性语言的本质区别是,编译性语言有个编译过程。
  • 理论上讲,解释性语言会比编译性语言慢很多。一般来说,C++的性能是Python性能的十倍以上。

注释

  • // 注释单行(Python中用#注释)
  • /* aaaaaaaaa */ 多行注释,注释内容写在符号/**/之间
  • VS中注释的快捷键是Ctrl + K + C,取消注释快捷键是Ctrl + K + U

程序入口

使用的是VS2017
在这里插入图片描述

编译文件,点一下标签栏 CMake(K) -> 全部生成 或者 全部重新生成

启动文件,选择后缀 *.exe 启动项来启动程序。

CMake是一种跨平台编译工具,比make更为高级,使用起来要方便得多。CMake主要是编写CMakeLists.txt文件,然后用cmake命令将CMakeLists.txt文件转化为make所需要的makefile文件,最后用make命令编译源码生成可执行程序或共享库(so(shared object))。

最外面的CMakeLists.txt文件:

# CMakeList.txt: 顶层 CMake 项目文件,在此处执行全局配置
# 并包含子项目。
#
cmake_minimum_required (VERSION 3.8)

project ("Test01")

# 包含子项目。
add_subdirectory ("Test01")

代码解读

  1. cmake文件中#代表的是注释,不用管,用来解释这行命令是用来干嘛的。
  2. cmake_minimum_required (VERSION 3.8)申明 cmake 要求的最低版本。
  3. project ("Test01")工程名字。
  4. add_subdirectory ("Test01")要去调用某个文件夹下的cmake,这样做的好处是,当程序很大的时候,管理起来很方便。

文件夹里面的CMakeLists.txt文件:

# CMakeList.txt: Test01 的 CMake 项目,在此处包括源代码并定义
# 项目特定的逻辑。
#
cmake_minimum_required (VERSION 3.8)

# 将源代码添加到此项目的可执行文件。
add_executable (Test01 "Test01.cpp" "Test01.h")

# TODO: 如有需要,请添加测试并安装目标。

代码解读

  1. add_executable (Test01 "Test01.cpp" "Test01.h") 把后面两个文件编译成可执行的文件,就是一个编译的过程。也就是要把哪些源文件编译成可执行的文件。

Test01.cpp文件:

// Test01.cpp: 定义应用程序的入口点。
//

#include "Test01.h"

using namespace std;

int main()
{
	cout << "Hello World" << endl;
	return 0;
}

代码解读

  1. 源代码的逻辑都是写到*.cpp文件中去。
  2. #include "Test01.h" 引用头文件Test01.h,类似于Python中的import
  3. using namespace std; 使用命名空间,有点类似于Python中的模块,例如torch模块。
  4. Python程序是从上往下执行,但C++不是,C++的程序入口是main()函数,整个工程文件只能有一个main()函数。
  5. 两个大括号{ }称为程序块(代码块),Python中的程序块采用缩进的方式,C++需要用{ }括起来,{ }配对使用。
  6. cout << "Hello World" << endl; 输出 Hello World

Test01.h文件:

// Test01.h: 标准系统包含文件的包含文件
// 或项目特定的包含文件。

#pragma once

#include <iostream>

// TODO: 在此处引用程序需要的其他标头。

代码解读

  • *.cpp源码文件(源文件),就是程序逻辑怎么去实现。*.h头文件,用来定义一些东西,比如定义一个类,包含一个库等,基本上就是在头文件去定义。(“定义”,就是告诉你有这个东西,但是不告诉你这个东西是怎么实现的。)
  • *.h文件被称为头文件,头文件通常用于变量,函数,类的定义。经常在*.h头文件定义一些东西,而在*.cpp中去实现这个定义。源文件和源文件之间,通过*.h文件发生关系。
  • 一般来说,C++中的代码中,#后面跟着一些东西,是C++的预处理指令。在编译的时候,执行的指令,称为预处理指令。
  • #pragma once 该指令表示,只允许导入一次。
  • #include <iostream> 要导入其他模块,这里模块是IO流。
  • #include 导入文件有两种方式,如果是 < >,表示系统的库,例如 #include <iostream> 。如果自己去定义的,就用 " " 去导入,例如 #include "Test01.h" 。程序运行的时候,把 < > 写成 " " ,程序不会出错,反之一样,但是习惯不好。习惯上按照前述内容的写法来写代码。

变量数据类型

  • 变量就是执行过程中可以被改变的量。
  • 变量由名称和值构成,通过=号修改变量。
  • 变量是有类型的,类型包括:数字(整形、浮点型),布尔型,字符串,枚举,指针,引用,类。
  • NULL变量代表没有。(空,Python中用None表示)
  • auto类型(C++是强类型语言,Python是弱类型语言。C++11之后,给个auto类型,可以自己去推断变量类型。)

基本类型

类型范围
char1个字节-128~127 或 0~255
unsigned char1个字节0~255
signed char1个字节-128~127
int4个字节-2,147,483,648~2,147,483,647
unsigned int4个字节0~4,294,967,295
signed int4个字节-2,147,483,648~2,147,483,647
short int2个字节-32,768~32,767
unsigned short int2个字节0~65,535
signed short int2个字节-32,768~32,767
long int8个字节-9,223,372,036,854,775,808~9,223,372,036,854,775,807
signed long int8个字节-9,223,372,036,854,775,808~9,223,372,036,854,775,807
unsigned long int8个字节0~18,446,744,073,709,551,615
float4个字节精度型占4个字节(32位)内存空间,+/- 3.4e +/- 38(~7个数字)
double8个字节双精度型占8个字节(64位)内存空间,+/- 1.7e +/- 308(~15个数字)
long double16个字节长双精度型占16个字节(128位)内存空间,可提供18~19位有效数字
wchar_t2或4个字节1个宽字符

类型解读

  1. unsigned ** 无符号类型。1个字节占8位,同一个字节,有符号类型(最高位是符号位)表达的范围小于无符号类型。
  2. 类型没有指明是有符号还是无符号的话,默认是有符号类型。
  3. 有符号无符号,只针对整型。
// var.h
//
#pragma once

#include<string>
#include<iostream>


void var_show();

//var.cpp
//

#include "var.h"

using namespace std;

void var_show() {
	int i = 0;
	cout << i << endl;  // endl 可以理解成换行

	float j = 2.2;
	cout << j << endl;

	// 无符号整型,没有负数。如果让k=-2,输出4294967294,相当于最高位变成了1
	// C++是比较危险的语言,如果不注意,编译器不会报错,但结果不对。
	unsigned int k = 2;  
	cout << k << endl;

	char c = 'a', d = 0x35;  // 单引号代表一个字符,0x35是一个ASCII码表。这里单引号不能替换成双引号,否则报错。
	cout << c << " " << d << endl;  // a 5

	string str1 = "hello";  // string不是内置类型,使用时先导入#include<string>
	cout << str1 << endl;  // hello

	char str2[] = "world";
	cout << str2 << endl;

	char str3[] = { 'L', 'i', 'e', 'W', 'e', 'i', '\0' };  // 字符串以 '\0' 结束,代表空字符
	cout << str3 << endl;  // LieWei
}

常量

  • const
  • #defined
  • 理解2进制,10进制,16进制
// constant.h
//
#pragma once

#include<iostream>


void constant_show();
//constant.cpp
//

#include "constant.h"

using namespace std;

#define PI 3.1415926  // 定义一个常量,但后面不加 ;    中间没有 =   (预处理指令)

void constant_show() {
	cout << PI << endl;  // 3.14159  显示精度损失了,因为没有加f

	const double e = 2.71;  // 定义了e,后面就不会改变了,一直是2.71
	cout << e << endl;  // 2.71

	const float b = 1.2f;  // 加f表示是一个浮点数
	cout << b << endl;  // 1.2

	const int c = 0x10;  // 16进制,逢16进1
	cout << c << endl;  // 16

	const int d = 0b10;  // 2进制
	cout << d << endl;  // 2
	
}

作用域

  • 在函数或一个代码块内部申明的变量,称为局部变量。
  • 在函数参数的定义中声明的变量,称为形式参数。
  • 在所有函数外部声明的变量,称为全局变量。(C++的作用域,外面不能使用局部变量,但里面可以使用全局变量)
  • 局部变量被定义时,系统不会对其初始化,您必须自行对其初始化
  • 理解作用域符号 :: (全局作用域符号,类似Python中的global)
// scope.h
//
#pragma once

#include<iostream>

void scope_show();
//scope.cpp
//

#include "scope.h"

using namespace std;

int a = 3;//全局变量,在函数外面定义的变量
int b;//未显示初始化的全局变量,系统自动初始化为0

int globle() {
	return 5;
}


void scope_show() {
	cout << a << " " << b << endl; //打印全局变量a和b  3 0

	int c = 0; //定义局部变量c,局部变量必须初始化,否则报错
	int a = 2; //定义局部变量a,局部变量必须初始化

	cout << c << " " << a << endl; //打印局部变量c和a  0 2

	cout << a<< " " << ::a << endl;//打印局部变量a和全局变量a  2 3

	{
		int d = 5; //定义块中变量d
	}
	//cout << d << endl; //试图打印出d,报错。从外面看不到里面的d,但是从里面可以看到外面的东西。

	cout << ::globle() << endl; //调用全局函数  5
}

// C++的作用域,外面不能使用局部变量,但里面可以使用全局变量

指针

  • 理解指针
  • 掌握指针运算符 *&
  • 理解 NULL 指针(空指针)和野指针

一个数据,一定存在计算机的空间里面,当要读取这个数据的时候,必须有一个指向,去指向这个空间,然后把数据取出来。这个指向,就是指针

Python 定义变量 a=3 的流程:

第1步: 开辟一个空间, 把3放进来
第2步: 给这个空间取名字叫a

C++ 定义变量 int a=3 的流程:

第1步: 开辟一个空间, 然后用一个指针指向这个空间, 指针名字叫a
第2步: 把3放入该空间

注意C++和Python创建变量的区别。很多语言,用Python这种创建变量的方式比较多。

// 表示有一个整型空间,该空间名字叫a
int a  

// 表示有一个指针,这个指针指向了某个整型空间,该指针的名字叫a。
// 这个指针没有初始化,所以不知道指向了哪个内存空间。这个时候的指针,称为野指针。
int *a  
// point.h
//
#pragma once

#include<iostream>


void point_show();

//point.cpp
//

#include "point.h"

using namespace std;

void point_show() {

	int  var = 20;   // 实际变量的声明
	int* ip;        // 指针变量的声明,*是指针运算符。

	ip = &var;       // 在指针变量中存储 var 的地址。ip 这个指针指向了 var 这个变量。

	cout << "Value of var variable: ";
	cout << var << endl;  // Value of var variable: 20

	// 输出在指针变量中存储的地址
	cout << "Address stored in ip variable: ";
	cout << ip << endl;  // Address stored in ip variable: 000000F2F1DFFCA4

	// 访问指针中地址的值
	cout << "Value of *ip variable: ";
	cout << *ip << endl;  // Value of *ip variable: 20  使用时的*,表示把指向的内容取出来。
}

数组

  • 理解一维数组和二维数组
  • 理解数组初始化
// array.h
//
#pragma once

#include<iostream>


void array_show();
//array.cpp
//

#include "array.h"

using namespace std;

void array_show() {

	// 创建一个数组,该数组被分配了40个字节的空间
	int a[10];  // a数组里有10个整数
	cout << sizeof(a) << endl;  // 内置函数,计算变量所占的内存空间   40   整型4个字节*10
	cout << a[1] << endl;  // -858993460  a[10]还没有初始化

	// 创建一个数组,并初始化它
	double b[5] = { 1000.2, 2.3, 3.4, 7.1, 50.7 };
	cout << b[3] << endl; //打印出数组的第3个元素  7.1
	cout << b[7] << endl; //越界取值,非常危险的操作  -9.25596e+61

	cout << "-----------------------------" << endl;

	// 使用指针的方式操作数组
	cout << b << endl; //打印数组的指针  00000032E319FD08
	cout << *b << endl; //取出第一个元素  1000.2
	cout << *(b + 1) << endl; //取出第二个元素  2.3
	cout << *(b + 7) << endl; //越界取值,非常危险的操作  -9.25596e+61

	cout << "-----------------------------" << endl;

	// 创建一个二维数组
	int c[3][4] = {
		{0, 1, 2, 3} ,   /*  初始化索引号为 0 的行 */
		{4, 5, 6, 7} ,   /*  初始化索引号为 1 的行 */
		{8, 9, 10, 11}   /*  初始化索引号为 2 的行 */
	};
	cout << c[1][2] << endl; //取出第1行第2列的值  6
	cout << c[1] << endl;//取出第1行第一个元素的指针  00000032E319FD58  c[1]相当于指向第一个维度的第一个元素的地址
}

代码解读

  1. sizeof() 是一个内置函数,计算变量所占的空间。
  2. 使用 { }初始化数组。
  3. b[5] 中的 b ,是一个指针,指向第一个元素的地址, *b 可以取出第一个元素。
  4. C++没有越界检查,可以越界取值,访问其他内存空间,非常危险,容易被黑客利用。C++能够越界取值,是因为整个数组操作的原理,是指针操作,指针操作没有任何限制。
  5. C++稍不留神就越界了,必须非常注意!

引用

  • 理解引用
  • 理解应用定义符号 & ,区别指针取址符号 &

引用,就是取别名,或者取外号。

// ref.h
//
#pragma once

#include<string>
#include<iostream>


void ref_show();

//ref.cpp
//

#include "ref.h"

using namespace std;

void ref_show() {
	// 声明简单的变量
	int    i=3;
	double d=4;

	// 声明引用变量
	int&    r = i;  // 在int后加&,就是取别名,将i和r关联起来。
	double& s = d;

	i = 5;
	cout << "Value of i : " << i << endl;  // Value of i : 5
	cout << "Value of i reference : " << r << endl;  // Value of i reference : 5

	d = 11.7;
	cout << "Value of d : " << d << endl;  // Value of d : 11.7
	cout << "Value of d reference : " << s << endl;  // Value of d reference : 11.7
}

代码解读

  1. 引用(取别名),就是在类型后面加 & ,别名必须和真实的名字关联起来,否则没有意义。别名,指的是同一个内存空间,值不变。

引用 vs 指针

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

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

	int* ip;  // 类型后面跟*,创建指针
	int& r = var; // 取别名

	ip = &var;    // var变量的指针ip
	*ip;  // 取指针指向内存空间的内容

	cout << var << endl;
	cout << r << endl;
	cout << ip << endl;  // 输出指针指向的地址
	cout << *ip << endl;
}

代码解读

  1. 注意不同位置的 * & 所表示的不同含义。

函数参数

  • 值传递
  • 指针传递
  • 引用传递

函数定义方法

函数都应该有一个返回值,Python中用关键字 def 定义的。

C++不用关键字定义,按照一定格式定义就行。如果没有返回值,定义成 void 类型;有返回值,返回值必须有个类型,比如 int

// 没有返回值
void fn(){
    函数体;
}

// 有返回值
int func(inta, intb){
    函数体;
    return **;
}
// param.h
//
#pragma once

#include<iostream>


void param_show();
//param.cpp
//

#include "param.h"

using namespace std;

//值传递
void swap_value(int x,int y) {
	int z = x;
	x = y;
	y = z;
}

//指针传递
void swap_point(int* x, int* y) {
	int z = *x;  // 把x的指向空间的值取出来给到z
	*x = *y;
	*y = z;
}

//引用传递
void swap_ref(int& x, int& y) {
	int z = x;
	x = y;
	y = z;
}

void param_show() {
	int a = 3, b = 4;
	swap_value(a, b);  // 因为是拷贝一份,所以 x, y中做任何操作,不会影响到 a, b
	cout << a << " " << b << endl;  // 3 4

	int c = 3, d = 4;
	swap_point(&c, &d);  // 把 c, d 的指针取出来传进去
	cout << c << " " << d << endl;  // 4 3

	int e = 3, f = 4;
	swap_ref(e, f);
	cout << e << " " << f << endl;  // 4 3
}

代码解读

  1. 函数有三种传参方式:值传递,指针传递,引用传递。
  2. 值传递,是把 a b 分别复制一份给 x yx y 做任何操作,不会影响到 a b
  3. 引用传递比较安全,调用方式和值传递差不多。像Python内部都是引用机制。

内存管理

  • 理解栈,理解变量在栈中的生命周期
  • 理解堆,理解堆的生命周期
  • 理解 newdeletenew[]delete[]
  • 理解内存泄漏的原理
  • 理解函数返回值不能是栈上的指针或引用

堆是在程序运行时,而不是在程序编译时,申请某个大小的内存空间。即动态分配内存,对其访问和对一般内存的访问没有区别。堆是指程序运行时申请的动态内存,而栈只是指一种使用堆的方法(即先进后出)。

如果是在程序块中定义了一个变量,会申请一个内存空间,当程序块执行完之后,就会把这个空间释放掉。这种空间就称为栈空间。

// memory.h
//
#pragma once

#include<iostream>


void memory_show();

//memory.cpp
//

#include "memory.h"
#include <Windows.h>

using namespace std;

//栈中变量的错误使用演示
void stack() {
	int* ptr_a = NULL;  // 指到空这个位置,也就是0的位置
	{
		int a = 3;//栈中声明一个变量a,当执行出作用域后,变量会被自动清理
		ptr_a = &a;
		cout << *ptr_a << endl;  // 3
	}
	cout << *ptr_a << endl; //  3  虽然能得到结果,但是这操作是错误的,因为这时候a已经被释放,或者马上要被释放掉,不再安全。

}

//堆
void heap() {
	int* ptr_a = NULL;
	{
		//在堆中声明一个变量,初始化值为3,并把该变量的指针传递给ptr_a指针变量
		ptr_a = new int(4);  // 新建一个整型空间,里面填一个值4
	}
	cout << *ptr_a << endl; //  4   这不会有任何问题,栈上这么操作不对,有隐患。

	delete ptr_a; // 如果不执行这句,内存会泄露
}

//泄露
void leak() {
	for (int i = 1; i < 1000000; i++) {
		int* a = new int[100000];  // 指向一个指针
		//int a[100000];  // 栈空间不用 delete,内存也不增大,会自动释放内存
		delete[] a;  // 堆空间如果内存不释放,会导致内存越来越大
		Sleep(1);
	}
}

void memory_show() {

	//stack();
	heap();
	//leak();


}

代码解读

  1. 局部变量都是在栈上申请的,栈一旦超出定义域(作用域),栈里面的内容就有可能被回收掉,这时候栈里面的内容不再安全了。栈的内存空间是自动回收和释放的。
  2. 堆,是全局的,在任何地方申请的堆空间,都是在同一个地方去申请。如果不用这块空间,需要手动释放掉。堆空间手动释放,栈空间自动释放。
  3. new 关键字是在堆上,申请(新建)一个空间。 delete ptr_a; 使用堆空间,一定要用这行代码手动释放,否则一直占用内存空间,容易导致内存泄漏(内存占用越来越多,最后爆掉)。
  4. new int[]delete[] , 如果申请内存空间是带了 [] ,是数组,删除时也必须带,配对使用的。不是数组,就不用带 []
  5. 对内存管理,是C++的一个难点

表达式

  • 算术运算符
  • 关系运算符
  • 逻辑运算符
  • 赋值运算符
int a = 1;
a++;  // 先取值在相加
++a;  // 先相加,再取值
// exp.h
//
#pragma once

#include<iostream>


void exp_show();
//exp.cpp
//

#include "exp.h"

using namespace std;

void arithmetic() {
	int a = 21;
	int b = 10;
	int c;

	c = a + b;
	cout << "Line 1 - c 的值是 " << c << endl;
	c = a - b;
	cout << "Line 2 - c 的值是 " << c << endl;
	c = a * b;
	cout << "Line 3 - c 的值是 " << c << endl;
	c = a / b; //2
	cout << "Line 4 - c 的值是 " << c << endl;
	c = a % b; //1
	cout << "Line 5 - c 的值是 " << c << endl;

	int d = 10;   //  测试自增、自减
	c = d++; //10,先赋值在++
	cout << "Line 6 - c 的值是 " << c << endl;
	c = ++d; //12 先加再赋值
	cout << "Line 6 - c 的值是 " << c << endl;


	d = 10;    // 重新赋值
	c = d--;
	cout << "Line 7 - c 的值是 " << c << endl;
}

void compare() {
	cout << (1 < 2) << endl;
	cout << (1 > 2) << endl;
	cout << (1 == 2) << endl;
	cout << (1 != 2) << endl;
	cout << (1 >= 1) << endl;
	cout << (1 <= 2) << endl;
	cout << "============" << endl;
}
	
void logic() {
	cout << (1 < 2 && 3 > 2) << endl;
	cout << (1 < 2 || 3 < 2) << endl;
	cout << !(1 < 2) << endl;
}

void assign() {
	int a = 21;
	int c;

	c = a;
	cout << "Line 1 - =  运算符实例,c 的值 = : " << c << endl;

	c += a;
	cout << "Line 2 - += 运算符实例,c 的值 = : " << c << endl;

	c -= a;
	cout << "Line 3 - -= 运算符实例,c 的值 = : " << c << endl;

	c *= a;
	cout << "Line 4 - *= 运算符实例,c 的值 = : " << c << endl;

	c /= a;
	cout << "Line 5 - /= 运算符实例,c 的值 = : " << c << endl;

	c = 200;
	c %= a;
	cout << "Line 6 - %= 运算符实例,c 的值 = : " << c << endl;


}

void exp_show() {
	arithmetic();
	compare();
	logic();
	assign();
}

代码解读

  1. C++中没有真正的布尔值,但可以去申请 a=True , 打印出来也会发现 a=1False 打印出来就是 0

流程控制

循环

  • for 循环
  • whiledo...while 循环
// loop.h
//
#pragma once

#include<iostream>


void loop_show();
//loop.cpp
//

#include "loop.h"

using namespace std;

//for循环
void for_loop() {
	int a[] = { 1,2,3,4,5,6 };
	for (int i = 0; i < 6; i++) {
		cout << a[i] << endl;
	}
}

//foreach循环
void foreach_loop() {
	int a[] = { 1,2,3,4,5,6 };
	for (int& k : a) {
		cout << k << endl;
	}
}

//while循环
void while_loop() {
	int a[] = { 1,2,3,4,5,6 };
	int i = 0;
	while (i < 5) {
		cout << a[i++] << endl;
	}
}

//do...while循环
void do_while_loop() {
	int a[] = { 1,2,3,4,5,6 };
	int i = 0;
	do {
		cout << a[i++] << endl;
	} while (i < 5);  // 先执行一次,再检查条件
}

void loop_show() {
	//for_loop();
	//foreach_loop();
	while_loop();
	//do_while_loop();
}

判断

  • if...else if...else
  • 三目运算符 exp?exp1:exp1
#pragma once

#include<iostream>

void judge_show();
//judge.cpp

#include "judge.h"
#include <string>

using namespace std;

void judge_show() {
	int a = 1;

	if (a == 1) {
		cout << "1" << endl;
	}
	else if (a == 2) {
		cout << "2" << endl;
	}
	else {
		cout << "other" << endl;
	}

	bool b = true;
	string c = b ? "True" : "False";
	cout << c << endl;
}

流程中断

  • continue
  • break
//interrupt.h
//

#pragma once

#include<iostream>

void interrupt_show();
//interrupt.cpp

#include "interrupt.h"

using namespace std;

void interrupt_show() {
	int a[] = { 0,1,2,3,4,5,6,7,8,9 };
	
	for (int i = 0; i < 10; i++) {
		if (a[i] == 5)
			continue;
		cout << a[i];
	}

	cout << "------------------------------" << endl;

	for (int i = 0; i < 10; i++) {
		if (a[i] == 5)
			break;
		cout << a[i];
	}
}

类与对象

类和对象基础

  • structclass 关键字定义类
  • 实例化类
  • 构造函数与析构函数
  • 属性与方法
  • 理解类成员操作符 .->
  • 理解 this

构造函数与析构函数

  1. 构造函数是一种特殊的成员函数,它主要用于为对象分配空间,进行初始化。
  2. 析构函数是一种特殊的成员函数,它执行与构造函数相反的操作,通常用于撤消对象时的一些清理任务,如释放分配给对象的内存空间等。
  3. 构造函数和析构函数在任何面向对象编程的语言里都有。
//clazz.h
//

#pragma once

#include<iostream>

void clazz_show();
//clazz.cpp

#include "clazz.h"
#include <string>

using namespace std;

struct Person {


	//属性
	string name;
	int age;

	//默认构造函数
	Person() {
		this->name = "liewei";
		this->age = 32;
	}

	//自定义构造函数
	Person(string name, int age) {
		this->name = name;
		this->age = age;
	}


	//方法
	void say() {
		cout << "my name is " << this->name << ", I am " << this->age << " year old." << endl;
	}

	//析构函数
	~Person()
	{
		cout << "person 已经被释放" << endl;
	}
};

void clazz_show() {
	{
		Person liewei;  //  创建实例
		liewei.age = 34;
		liewei.say();
	}
	cout << "----------------------" << endl;

	{
		Person* zhang = new Person("zhang3", 25);
		zhang->say();
		(*zhang).say();
	}
	cout << "**********************" << endl;
	
}

代码解读

  1. Python中使用 self 就可以定义属性,但C++中属性必须明确定义出来,而且放在方法的外面的。
  2. C++中构造函数是没有返回值的,而且名字和类名必须一摸一样
  3. 同一个作用域下,两个函数的函数名 Person() 相同,参数名不同,叫做函数重载。如果两个函数的函数名和参数名都相同,就不叫函数重载,会报错。Python不支持函数重载的。
  4. 析构函数的定义,是在函数名前加一个 ~ 号,函数名必须和类名一样。析构函数是没有参数的。
  5. this 类似于 self ,但在C++中是一个指针。如果是一个对象,用 . 去操作;如果是一个属性或者方法,用 -> 操作。

类权限

  • 私有成员(private)、保护成员(protected)和公有成员(public)
  • class 默认为 privatestruct 默认为 public

私有成员(private):外面不能操作

保护成员(protected):只有继承的才能操作

公有成员(public):都能操作

继承

  • 理解继承
  • 理解函数覆盖
  • 理解虚函数
  • 理解纯虚函数
  • 扩展:析构函数我们尽量声明为虚函数,构造函数不能为虚函数
//inherit.h
//

#pragma once

#include<iostream>

void inherit_show();
//inherit.cpp

#include "inherit.h"
#include <string>

using namespace std;

class Animal {

protected:  //将私有改为保护
	string m_sex;//公或母


public:
	//构造函数,用冒号初始化成员变量
	//class默认是私有,构造函数必须在公共区域,否则无法实例化
	Animal(string sex) :m_sex(sex) {}  // 简便的初始化写法

	//定义一个纯虚方法
	//virtual void say() = 0;

	//定义一个虚方法
	/*virtual void say() {
		cout << "What is the sex of the Animal ?" << endl;
	}*/

	//定义一个普通方法
	void say() {
		cout << "What is the sex of the Animal ?" << endl;
	}

};

class Cat :public Animal {

public:
	Cat(string sex) :Animal(sex) {}

	void say() {
		cout << "This cat's sex is " << this->m_sex << "." << endl;
	}
};

void inherit_show() {
	//Cat* mycat = new Cat("公");
	Animal* mycat = new Cat("公");  //普通函数以前面来执行,虚函数以后面来判断执行
	mycat->say();
	delete mycat;

}

代码解读

  1. 除了构造函数之外,其他的函数,如果要用来继承,都应该是虚函数。

运算符重载

  • 运算符是可以重载的

模板

函数模板

  • 理解函数模板
  • 理解函数模板与函数重载
  • 理解静态编译和动态编译

如果不同的类之间有共同的属性,希望只定义一个函数就可以搞定,所以需要用到函数模板。

Python是弱类型语言,所以不用担心这个。C++是强类型语言,这个问题就不简单了。

//fun_temp.h
//

#pragma once

#include<iostream>

void fun_temp_show();

//fun_temp.cpp

#include <iostream>

using namespace std;

template <typename T>  // 声明一个模板叫T
T add(T& a, T& b) {  // & 是引用
	 return a + b;  // 返回值不要传局部变量的指针和引用,否则会遇到大麻烦,说不定哪天程序就崩溃了。可以通过值返回,或传堆回去
}

void fun_temp_show() {
	float x = 3.1f, y = 4.33f;
	cout << add(x, y) << endl;
}

类模板

模板,就是在强类型语言中,让写的代码更加精简。

//clazz_temp.h
//

#pragma once

#include<iostream>

void clazz_temp_show();

//clazz_temp.cpp

#include <iostream>

using namespace std;

template <class T>
struct Pair {
	T m_first;// 不知道类型,用一个泛性模板代替
	T m_second;

	Pair(T first,T second):m_first(first),m_second(second){}

	T sum() {
		return m_first + m_second;
	}
};

void clazz_temp_show() {
	double x = 3.1, y = 4.2;
	Pair<double> p(x, y);
	cout << p.sum() << endl;
}

STL

简介

  • C++ STL(标准模板库)是一套功能强大的C++模板类,提供了通用的模板类和函数,这些模板类和函数可以实现多种流行和常用的算法和数据结构,如向量、链表、队列、栈。
  • C++ 标准模板库的核心包括以下三个组件
组件描述
容器(Containers)容器是用来管理某一类对象的集合。C++提供了各种不同类型的容器,比如 deque、list、vector、map 等。
算法(Algorithms)算法作用于容器。它们提供了执行各种操作的方式,包括对容器内容执行初始化、排序、搜索和转换等操作。
迭代器(iterators)迭代器用于遍历对象集合的元素。这些集合可能是容器,也可能是容器的子集。
// stl_vector.h
//
#pragma once

#include<iostream>


void stl_vector_show();
//stl_vector.cpp
//

#include "stl_vector.h"
#include <vector>
#include <string>

using namespace std;

void stl_vector_show() {

	// 创建一个向量存储 int
	vector<int> vec;
	int i;

	// 显示 vec 的原始大小
	cout << "vector size = " << vec.size() << endl;

	// 推入 5 个值到向量中
	for (i = 0; i < 5; i++) {
		vec.push_back(i);
	}

	// 显示 vec 扩展后的大小
	cout << "extended vector size = " << vec.size() << endl;

	// 访问向量中的 5 个值
	for (i = 0; i < 5; i++) {
		cout << "value of vec [" << i << "] = " << vec[i] << endl;
	}

	// 使用迭代器 iterator 访问值
	vector<int>::iterator v = vec.begin();
	while (v != vec.end()) {
		cout << "value of v = " << *v << endl;
		v++;
	}
}

输出结果

vector size = 0
extended vector size = 5
value of vec [0] = 0
value of vec [1] = 1
value of vec [2] = 2
value of vec [3] = 3
value of vec [4] = 4
value of v = 0
value of v = 1
value of v = 2
value of v = 3
value of v = 4



备注:部分内容摘录自其它网站,若有侵权,请联系作者删除!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值