本文为博主自学C++的总结文档,相当于记个笔记。博主学习的资料来源于菜鸟教程,博客中的很多资料以及截图也是来源于菜鸟,个人感觉挺清晰明了的,但是最好有其他语言的基础再去学习,不然直接看会感觉比较绕。
本文划分为三个阶段
一、初级阶段
初级阶段为C++ 的基础知识,基本语法,数据类型,变量类型以及数组指针等基本知识的了解,和C语言的内容基本一致。
二、中级阶段
中级阶段主要为类,对象,继承,多态,重载,数据封装以及数据抽象等 C++区别于C语言的功能介绍,核心内容需要系统的学习与掌握。
三、高级阶段
高级阶段为C++的应用层面,例如文件和流,异常处理,动态内存,命名空间,信号处理,多线程,以及Web编程等知识,可以先做简单了解,实际应用时再做深入了解。
一、初级总结
由于初级阶段内容比较简单,如果有其他语言基础会很快的就能学会,所以这里只总结了一些初级阶段的重点部分。
1.1、C++关键字
全部关键字的定义与介绍见 关键字 https://www.runoob.com/w3cnote/cpp-keyword-intro.html
1.2、命名空间
举个例子吧,我们的名字,有很多时候会重名,比如张三。
世界上可能有几十几百个张三。我们的世界里当然可以用身份证号码来分啦,但在没有身份证的时代怎么分呢?
有办法的,比如,可以在名字前面加上地方名,如
广东的张三 上海的张三
同理程序员设计变量时候可能会有很多相同的内容,所设计的变量名也相同,于是可以使用命名空间来划分。
例如:小李与小韩均新建了一个变量 flag,但是一个是int型一个是bool型,为了将其区分开来。
namespace Li{ //小李的变量声明
int flag = 1;
}
namespace Han{ //小韩的变量声明
bool flag = true;
}
使用命名空间,便可将其区分开来
Li::flag = 0; //使用小李定义的变量flag
Han::flag = false; //使用小韩定义的变量flag
1.3、数据类型
(一)typedef声明
(二)枚举类型
如果变量只有某几种可能,则可以定义为枚举(enumeration)类型。所谓"枚举"是指将变量的值一一列举出来,变量的值只能在列举出来的值的范围内。
关键字:enum
例如:
enum color { red, green, blue } c;
c = blue; c的取值范围只能是 red,greeen,blue三个值中的一个。
(三)结构体
结构体是 C++ 中一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项。
结构体用于表示一条记录,假设您想要跟踪图书馆中书本的动态,您可能需要跟踪每本书的下列属性: Title :标题 Author :作者 Subject :类目 Book ID :书的 ID
范例:
(四) 修饰符类型
- signed 有符号的() 数据有正负号
- unsigned 无符号的() 数据只有正号没有负号
- long 长的() 字节数是原来字节的一倍 例如 long int 为8个字节
- short 短的() 字节数为原来的1/2 例如 short int 为4个字节
- const 常熟,常量 const 类型的对象在程序执行期间不能被修改改变。
- volatile 修饰符 volatile 告诉编译器不需要优化volatile声明的变量,让程序可以直接从内存中读取变量。对于一般的变量编译器会对变量进行优化,将内存中的变量值放在寄存器中以加快读写效率。
1.4、数组与指针
数组与指针的使用就不介绍了,与C语言一致,这里主要介绍数组与指针的共通之处 ↵
& 取指针符号
* 取指针所在地址保存的数据
指针和数组是密切相关的。事实上,指针和数组在很多情况下是可以互换的。
uint8_t *ptr; //定义个指针变量
ptr[0] 与 *ptr 意义相同 ptr[1] 与 *(ptr+1)意义相同
例如,一个指向数组开头的指针,可以通过使用指针的算术运算或数组索引来访问数组。请看下面的程序:
二、中级总结
中级总结是C++的核心内容,必须要认真学习。
2.1、类与对象
类定义是以关键字 class 开头,后跟类的名称。类的主体是包含在一对花括号中。类定义后必须跟着一个分号或一个声明列表。例如,我们使用关键字 class 定义 Box 数据类型,如下所示:
Box 就是一个类 ,类相当于一个模板。类里面有各种数据,各种类的成员函数。C++语言可以通过这些模块制造创造自己的对象。
Box box1 box1与box2就是按照Box模块所创造出来的对象,虽然box1与box2都是Box创造的对象,但是box1与box2二者没有任何直接联系。
Box box2
对象可以直接调用类种的数据与成员函数,范例如下
#include <iostream>
using namespace std;
class Box
{
public:
double length; // 长度
double breadth; // 宽度
double height; // 高度
// 成员函数声明
double get(void);
void set( double len, double bre, double hei );
};
// 成员函数定义
double Box::get(void)
{
return length * breadth * height;
}
void Box::set( double len, double bre, double hei)
{
length = len;
breadth = bre;
height = hei;
}
int main( )
{
Box Box1; // 声明 Box1,类型为 Box
Box Box2; // 声明 Box2,类型为 Box
Box Box3; // 声明 Box3,类型为 Box
double volume = 0.0; // 用于存储体积
// box 1 详述
Box1.height = 5.0;
Box1.length = 6.0;
Box1.breadth = 7.0;
// box 2 详述
Box2.height = 10.0;
Box2.length = 12.0;
Box2.breadth = 13.0;
// box 1 的体积
volume = Box1.height * Box1.length * Box1.breadth;
cout << "Box1 的体积:" << volume <<endl;
// box 2 的体积
volume = Box2.height * Box2.length * Box2.breadth;
cout << "Box2 的体积:" << volume <<endl;
// box 3 详述
Box3.set(16.0, 8.0, 12.0);
volume = Box3.get();
cout << "Box3 的体积:" << volume <<endl;
return 0;
}
该范例的运行结果为
2.2、类访问修饰符
类访问修饰符一共有三种,分别是 public、private、protected
公有(public )成员
公有成员在类的外部是可访问的。您可以不使用任何成员函数来设置和获取公有变量的值。
私有(private)成员
私有成员变量或函数在类的外部是不可访问的,甚至是不可查看的。只有类和友元函数可以访问私有成员。
protected(受保护)成员
protected(受保护)成员变量或函数与私有成员十分相似,但有一点不同,protected(受保护)成员在派生类(即子类)中是可访问的。
类中如果不加任何修饰符,变量默认认为是 private成员
2.3、C++继承
面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易。这样做,也达到了重用代码功能和提高执行效率的效果。
当创建一个类时,您不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类(父类),新建的类称为派生类(子类)
类在继承时需要添加修饰符
例如: class aaa:public bbb 其中 aaa为派生类,bbb为基类,继承类型为公有继承。
范例:
#include <iostream>
using namespace std;
// 基类
class Shape
{
public:
void setWidth(int w)
{
width = w;
}
void setHeight(int h)
{
height = h;
}
protected:
int width;
int height;
};
// 派生类
class Rectangle: public Shape
{
public:
int getArea()
{
return (width * height);
}
};
int main(void)
{
Rectangle Rect;
Rect.setWidth(5);
Rect.setHeight(7);
// 输出对象的面积
cout << "Total area: " << Rect.getArea() << endl;
return 0;
}
最终输出打印为
继承分为公有继承,保护继承,和私有继承,下面是三种继承的区别。
多继承
多继承即一个子类可以有多个父类,它继承了多个父类的特性。
C++ 类可以从多个类继承成员,语法如下:
class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,… { <派生类类体> };
例如:
#include <iostream>
using namespace std;
// 基类 Shape
class Shape
{
public:
void setWidth(int w)
{
width = w;
}
void setHeight(int h)
{
height = h;
}
protected:
int width;
int height;
};
// 基类 PaintCost
class PaintCost
{
public:
int getCost(int area)
{
return area * 70;
}
};
// 派生类
class Rectangle: public Shape, public PaintCost
{
public:
int getArea()
{
return (width * height);
}
};
int main(void)
{
Rectangle Rect;
int area;
Rect.setWidth(5);
Rect.setHeight(7);
area = Rect.getArea();
// 输出对象的面积
cout << "Total area: " << Rect.getArea() << endl;
// 输出总花费
cout << "Total paint cost: $" << Rect.getCost(area) << endl;
return 0;
}
当软件被编译运行后
2.4、重载运算符与重载函数
重载运算符
您可以重定义或重载大部分 C++ 内置的运算符。这样,您就能使用自定义类型的运算符。
重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。
例如:重载 + 运算符
重载函数
在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。您不能仅通过返回类型的不同来重载函数。
例如:
#include <iostream>
using namespace std;
class printData
{
public:
void print(int i) {
cout << "整数为: " << i << endl;
}
void print(double f) {
cout << "浮点数为: " << f << endl;
}
void print(char c[]) {
cout << "字符串为: " << c << endl;
}
};
int main(void)
{
printData pd;
// 输出整数
pd.print(5);
// 输出浮点数
pd.print(500.263);
// 输出字符串
char c[] = "Hello C++";
pd.print(c);
return 0;
}
同为print函数,但其实现的功能不一样,代码编译并运行后的结果如下
2.5、构造函数与析构函数
类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。
构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。
类的析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。
析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。
构造函数在创建对象时会自动运行一次,多用于初始化成员变量。
析构函数在删除对象时会自动运行,用于关闭文件,释放内存
2.6、this指针与静态成员变量
在 C++ 中,每一个对象都能通过 this 指针来访问自己的地址。this 指针是所有成员函数的隐含参数。因此,在成员函数内部,它可以用来指向调用对象。
在类的成员函数中,可以使用 this-> 来调用其他的成员函数或者成员变量。
静态成员变量与静态成员函数
静态成员变量: 我们可以使用 static 关键字来把类成员定义为静态的。当我们声明类的成员为静态时,这意味着无论创建多少个类的对象,静态成员都只有一个副本。
静态成员函数: 使用 static 定义静态成员函数即使在类对象不存在的情况下也能被调用,静态函数只要使用类名加范围解析运算符 :: 就可以访问。静态成员函数只能访问静态成员数据、其他静态成员函数和类外部的其他函数。
静态成员函数有一个类范围,他们不能访问类的 this 指针。
例如:box1 与 box2均为声明的对象,但是在调用静态函数时,可以直接用 类名::函数名来调用 Box::getCount()
2.7、多态与虚函数
多态按字面的意思就是多种形态。当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。
C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。
虚函数 是在基类中使用关键字 virtual 声明的函数。在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。
我们想要的是在程序中任意点可以根据所调用的对象类型来选择调用的函数,这种操作被称为动态链接,或后期绑定。
就是一个基类的不同派生类中,拥有某个同名的函数,编译器不知道调用哪个,如果将基类前声明 virtual ,那么编译器
会自动绑定派生类的函数。
#include <iostream>
using namespace std;
class Shape {
protected:
int width, height;
public:
Shape( int a=0, int b=0)
{
width = a;
height = b;
}
virtual int area()
{
cout << "Parent class area :" <<endl;
return 0;
}
};
class Rectangle: public Shape{
public:
Rectangle( int a=0, int b=0):Shape(a, b) { }
int area ()
{
cout << "Rectangle class area :" <<endl;
return (width * height);
}
};
class Triangle: public Shape{
public:
Triangle( int a=0, int b=0):Shape(a, b) { }
int area ()
{
cout << "Triangle class area :" <<endl;
return (width * height / 2);
}
};
// 程序的主函数
int main( )
{
Shape *shape;
Rectangle rec(10,7);
Triangle tri(10,5);
// 存储矩形的地址
shape = &rec;
// 调用矩形的求面积函数 area
shape->area();
// 存储三角形的地址
shape = &tri;
// 调用三角形的求面积函数 area
shape->area();
return 0;
}
这种情况下运行的就是各派生类的成员函数了,而不会绑定到基类的成员函数。即一个同名函数,多个定义。
三、高级总结
高级总结是C++的一些应用层面的东西,需要具体问题具体分析,可先简单了解,等实际应用时再深入学习,这部分可以直接去看菜鸟的教程即可
3.1、文件与流
C++ 中处理文件必须要用到以下三个库
关键函数
1、open :功能以某种模式打开某个文件,具体模式包括 读、写、追加、定位在末尾,截断等。
void open(const char *filename, ios::openmode mode); 打开文件 第一个参数为文件名与文件位置,第二个参数为打开文件的模式,具体模式见下表
范例:以读写模式打开文件 file.dat
ifstream afile;
afile.open("file.dat", ios::out | ios::in );
2、close:关闭文件 关闭打开的文件
void close();
范例:关闭上面的文件 file.dat
afile.close();
3、<< : 写入信息 在 C++ 编程中,我们使用流插入运算符( << )向文件写入信息
范例 : 向打开的文件中写入数据data
outfile << data << endl;
4、 >> : 读取信息 在 C++ 编程中,我们使用 流插入运算符( >> )从文件中读取信息
范例: 从打开的文件中读取数据
infile >> data;
5、文件位置的处理,在对文件进行读写时会使用到文件位置的处理函数,具体的使用方法如下。