文章目录
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")
代码解读
cmake
文件中#
代表的是注释,不用管,用来解释这行命令是用来干嘛的。cmake_minimum_required (VERSION 3.8)
申明cmake
要求的最低版本。project ("Test01")
工程名字。add_subdirectory ("Test01")
要去调用某个文件夹下的cmake
,这样做的好处是,当程序很大的时候,管理起来很方便。
文件夹里面的CMakeLists.txt
文件:
# CMakeList.txt: Test01 的 CMake 项目,在此处包括源代码并定义
# 项目特定的逻辑。
#
cmake_minimum_required (VERSION 3.8)
# 将源代码添加到此项目的可执行文件。
add_executable (Test01 "Test01.cpp" "Test01.h")
# TODO: 如有需要,请添加测试并安装目标。
代码解读
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;
}
代码解读
- 源代码的逻辑都是写到
*.cpp
文件中去。 #include "Test01.h"
引用头文件Test01.h
,类似于Python中的import
。using namespace std;
使用命名空间,有点类似于Python中的模块,例如torch
模块。- Python程序是从上往下执行,但C++不是,C++的程序入口是
main()
函数,整个工程文件只能有一个main()
函数。 - 两个大括号
{ }
称为程序块(代码块),Python中的程序块采用缩进的方式,C++需要用{ }
括起来,{ }
配对使用。 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
类型,可以自己去推断变量类型。)
基本类型
类型 | 位 | 范围 |
---|---|---|
char | 1个字节 | -128~127 或 0~255 |
unsigned char | 1个字节 | 0~255 |
signed char | 1个字节 | -128~127 |
int | 4个字节 | -2,147,483,648~2,147,483,647 |
unsigned int | 4个字节 | 0~4,294,967,295 |
signed int | 4个字节 | -2,147,483,648~2,147,483,647 |
short int | 2个字节 | -32,768~32,767 |
unsigned short int | 2个字节 | 0~65,535 |
signed short int | 2个字节 | -32,768~32,767 |
long int | 8个字节 | -9,223,372,036,854,775,808~9,223,372,036,854,775,807 |
signed long int | 8个字节 | -9,223,372,036,854,775,808~9,223,372,036,854,775,807 |
unsigned long int | 8个字节 | 0~18,446,744,073,709,551,615 |
float | 4个字节 | 精度型占4个字节(32位)内存空间,+/- 3.4e +/- 38(~7个数字) |
double | 8个字节 | 双精度型占8个字节(64位)内存空间,+/- 1.7e +/- 308(~15个数字) |
long double | 16个字节 | 长双精度型占16个字节(128位)内存空间,可提供18~19位有效数字 |
wchar_t | 2或4个字节 | 1个宽字符 |
类型解读
unsigned **
无符号类型。1个字节占8位,同一个字节,有符号类型(最高位是符号位)表达的范围小于无符号类型。- 类型没有指明是有符号还是无符号的话,默认是有符号类型。
- 有符号无符号,只针对整型。
// 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
的流程:
C++ 定义变量 int a=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]相当于指向第一个维度的第一个元素的地址
}
代码解读
sizeof()
是一个内置函数,计算变量所占的空间。- 使用
{ }
初始化数组。 b[5]
中的b
,是一个指针,指向第一个元素的地址,*b
可以取出第一个元素。- C++没有越界检查,可以越界取值,访问其他内存空间,非常危险,容易被黑客利用。C++能够越界取值,是因为整个数组操作的原理,是指针操作,指针操作没有任何限制。
- 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
}
代码解读
- 引用(取别名),就是在类型后面加
&
,别名必须和真实的名字关联起来,否则没有意义。别名,指的是同一个内存空间,值不变。
引用 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;
}
代码解读
- 注意不同位置的
*
&
所表示的不同含义。
函数参数
- 值传递
- 指针传递
- 引用传递
函数定义方法
函数都应该有一个返回值,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
}
代码解读
- 函数有三种传参方式:值传递,指针传递,引用传递。
- 值传递,是把
a
b
分别复制一份给x
y
,x
y
做任何操作,不会影响到a
b
。 - 引用传递比较安全,调用方式和值传递差不多。像Python内部都是引用机制。
内存管理
- 理解栈,理解变量在栈中的生命周期
- 理解堆,理解堆的生命周期
- 理解
new
,delete
和new[]
,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();
}
代码解读
- 局部变量都是在栈上申请的,栈一旦超出定义域(作用域),栈里面的内容就有可能被回收掉,这时候栈里面的内容不再安全了。栈的内存空间是自动回收和释放的。
- 堆,是全局的,在任何地方申请的堆空间,都是在同一个地方去申请。如果不用这块空间,需要手动释放掉。堆空间手动释放,栈空间自动释放。
new
关键字是在堆上,申请(新建)一个空间。delete ptr_a;
使用堆空间,一定要用这行代码手动释放,否则一直占用内存空间,容易导致内存泄漏(内存占用越来越多,最后爆掉)。new int[]
和delete[]
, 如果申请内存空间是带了[]
,是数组,删除时也必须带,配对使用的。不是数组,就不用带[]
。- 对内存管理,是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();
}
代码解读
- C++中没有真正的布尔值,但可以去申请
a=True
, 打印出来也会发现a=1
,False
打印出来就是0
。
流程控制
循环
for
循环while
和do...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];
}
}
类与对象
类和对象基础
struct
和class
关键字定义类- 实例化类
- 构造函数与析构函数
- 属性与方法
- 理解类成员操作符
.
和->
- 理解
this
构造函数与析构函数
- 构造函数是一种特殊的成员函数,它主要用于为对象分配空间,进行初始化。
- 析构函数是一种特殊的成员函数,它执行与构造函数相反的操作,通常用于撤消对象时的一些清理任务,如释放分配给对象的内存空间等。
- 构造函数和析构函数在任何面向对象编程的语言里都有。
//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;
}
代码解读
- Python中使用
self
就可以定义属性,但C++中属性必须明确定义出来,而且放在方法的外面的。 - C++中构造函数是没有返回值的,而且名字和类名必须一摸一样。
- 同一个作用域下,两个函数的函数名
Person()
相同,参数名不同,叫做函数重载。如果两个函数的函数名和参数名都相同,就不叫函数重载,会报错。Python不支持函数重载的。 - 析构函数的定义,是在函数名前加一个
~
号,函数名必须和类名一样。析构函数是没有参数的。 this
类似于self
,但在C++中是一个指针。如果是一个对象,用.
去操作;如果是一个属性或者方法,用->
操作。
类权限
- 私有成员(private)、保护成员(protected)和公有成员(public)
class
默认为private
,struct
默认为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;
}
代码解读
- 除了构造函数之外,其他的函数,如果要用来继承,都应该是虚函数。
运算符重载
- 运算符是可以重载的
模板
函数模板
- 理解函数模板
- 理解函数模板与函数重载
- 理解静态编译和动态编译
如果不同的类之间有共同的属性,希望只定义一个函数就可以搞定,所以需要用到函数模板。
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
备注:部分内容摘录自其它网站,若有侵权,请联系作者删除!