有了C语言的基础,顺便把C++给学了,顺手记下了一些笔记,留着日后用。有需要的同学也可以参考一下,不过记得比较精简,所以可能看不懂,有不对或者看不明白的地方可以提出来学习学习哈。
C++与C相比
- 直接套用:注视、变量作用域、修饰符、循环、判断、函数、数组、日期&时间、数据结构、预处理
- 改进:
- 数据类型
- 布尔型 bool
- 宽字符型 wchar_t 位:2或4字节 范围:1个宽字符 用于Unicode包含的国家语言等
- 变量类型
- bool:存储值 true 或 false。
- wchar_t
- 常量
- 布尔常量:true 值代表真,false 值代表假。
- 存储类
- mutable(后续讲解)
- thread_local
- 仅可在它在其上创建的线程上访问。 变量在创建线程时创建,并在销毁线程时销毁。 每个线程都有其自己的变量副本。
- thread_local 说明符可以与 static 或 extern 合并。
- 可以将 thread_local 仅应用于数据声明和定义,thread_local 不能用于函数声明或定义。
- 字符串
- string类
- 支持c风格字符串操作
- 可以进行 =, +, str.size() 等操作(后续讲解)
- string类
- I / O
- 流:C++ 的 I/O 发生在流中,流是字节序列。如果字节流是从设备(如键盘、磁盘驱动器、网络连接等)流向内存,这叫做输入操作。如果字节流是从内存流向设备(如显示屏、打印机、磁盘驱动器、网络连接等),这叫做输出操作。
- 头文件:
- 数据类型
头文件 | 函数和描述 |
<iostream> | 该文件定义了 cin、cout、cerr 和 clog 对象,分别对应于标准输入流、标准输出流、非缓冲标准错误流和缓冲标准错误流。 |
<iomanip> | 该文件通过所谓的参数化的流操纵器(比如 setw 和 setprecision),来声明对执行标准化 I/O 有用的服务。 |
<fstream> | 该文件为用户控制的文件处理声明服务。我们将在文件和流的相关章节讨论它的细节。 |
标准输出流(cout):cout 是与流插入运算符 << 结合使用的 (cout << "Value of str is : " << str << endl;)。流插入运算符 << 在一个语句中可以多次使用,如上面实例中所示,endl 用于在行末添加一个换行符。标准输入输出流(cin):cin 是与流提取运算符 >> 结合使用的(cin >> name;)。标准错误流(cerr):cerr 对象附属到标准错误设备,通常也是显示屏,但是 cerr 对象是非缓冲的,且每个流插入到 cerr 都会立即输出。标准日志流(clog):。clog 对象附属到标准错误设备,通常也是显示屏,但是 clog 对象是缓冲的。这意味着每个流插入到 clog 都会先存储在缓冲在,直到缓冲填满或者缓冲区刷新时才会输出。clog 也是与流插入运算符 << 结合使用的。
- 引用:引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字。一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。
- 类&对象
- 定义类:class 类名称{public:内容};
- 定义对象:类名称 对象名称;
- 访问数据成员:类的对象的public数据成员可以使用直接成员访问运算符 (.) 来访问,protected和private不能。
- 类成员函数:
- 成员函数可以定义在类定义内部,或者单独使用范围解析运算符 :: 来定义。例如:double Box::getVolume(void)
- :: 可以不跟类名,表示全局数据或全局函数(即非成员函数)。
- 访问修饰符:类成员的访问限制是通过在类主体内部对各个区域标记 public、private(默认)、protected 来指定的。
- 私有成员变量或函数在类的外部是不可访问的,甚至是不可查看的。只有类和友元函数可以访问私有成员。
- 保护成员变量或函数与私有成员十分相似,但有一点不同,保护成员在派生类(即子类)中是可访问的。
- 继承中的特点
- public 继承:基类 public 成员,protected 成员,private 成员的访问属性在派生类中分别变成:public, protected, private
- protected 继承:基类 public 成员,protected 成员,private 成员的访问属性在派生类中分别变成:protected, protected, private
- private 继承:基类 public 成员,protected 成员,private 成员的访问属性在派生类中分别变成:private, private, private
- 构造函数&折构函数
- 类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。构造函数可用于为某些成员变量设置初始值。
- 使用初始化列表来初始化字段:C::C( double a, double b, double c): X(a), Y(b), Z(c) { .... }
- 类的析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。
- 拷贝构造函数(不理解!!!)
- 友元函数:类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。
- 声明:在类定义中该函数原型前使用关键字 friend
- 声明类 ClassTwo 的所有成员函数作为类 ClassOne 的友元,需要在类 ClassOne 的定义中放置如下声明:friend class ClassTwo;
- 内联函数:空间代价换时间的节省。
- 如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方。
- 定义:在函数名前面放置关键字 inline,在调用函数之前需要对函数进行定义;在类定义中的定义的函数都是内联函数,即使没有使用 inline 说明符。
- 优点:当函数体比较小的时候, 内联该函数可以令目标代码更加高效
- 注意:一定要小巧!内联包含循环或 switch 语句的函数常常是得不偿失!
- this指针
- 每一个对象都能通过 this 指针来访问自己的地址。this 指针是所有成员函数的隐含参数。因此,在成员函数内部,它可以用来指向调用对象。
- 友元函数没有 this 指针,因为友元不是类的成员。只有成员函数才有 this 指针。
- 用成员访问运算符 -> 访问类的对象或结构内的成员。
- 静态成员:无论创建多少个类的对象,静态成员都只有一个副本,把成员和任何一个对象独立开来
- 定义:前面加static关键字
- 如果不存在其他的初始化语句,在创建第一个对象时,所有的静态数据都会被初始化为零。
- 静态成员函数
- 静态成员函数只能访问静态成员数据、其他静态成员函数和类外部的其他函数。
- 没有 this 指针
- 可以使用静态成员函数来判断类的某些对象是否已被创建。
- 静态成员变量在类中仅仅是声明,没有定义,所以要在类的外面定义,实际上是给静态成员变量分配内存。
- 继承
- 达到了重用代码功能和提高执行时间的效果。
- 基类&派生类
- class derived-class: access-specifier base-class
- 一个类可以派生自多个类
- 访问控制和继承
- 访问权限
访问 | public | protected | private |
同一个类 | yes | yes | yes |
派生类 | yes | yes | no |
外部的类 | yes | no | no |
一个派生类继承了所有的基类方法,但下列情况除外:
- 基类的构造函数、析构函数和拷贝构造函数。
- 基类的重载运算符。
- 基类的友元函数。
继承类型多继承:class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…{<派生类类体>};虚继承(什么意思??)重载运算符和重载函数:C++ 允许在同一作用域中的某个运算符和函数指定多个定义
- 重载决策:编译器通过把您所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。
- 函数重载:同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。您不能仅通过返回类型的不同来重载函数。
- 运算符重载:
- 重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。
- 对象的属性使用 this 运算符进行访问
- 不可重载的运算符列表:
- .:成员访问运算符
- .*, ->*:成员指针访问运算符
- :::域运算符
- sizeof:长度运算符
- ?::条件运算符
- #: 预处理符号
多态:C++多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数;
- 多态条件
- 必须存在继承关系;
- 继承关系必须有同名虚函数(其中虚函数是在基类中使用关键字 virtual 声明的函数,在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数); 静态多态:函数调用在程序执行前就准备好了。有时候这也被称为早绑定,因为 area() 函数在程序编译期间就已经设置好了。
- 存在基类类型的指针或者引用,通过该指针或引用调用虚函数;
- 纯虚函数声明如下: virtual void funtion1()=0; 纯虚函数一般没有定义。包含纯虚函数的类是抽象类,抽象类不能定义实例,但可以声明指向实现该抽象类的具体类的指针或引用。
- 虚函数声明如下:virtual ReturnType FunctionName(Parameter) 虚函数必须实现。需要实例化的虚函数必须实现。
- 实现了纯虚函数的子类,该纯虚函数在子类中就编程了虚函数,子类的子类即孙子类可以覆盖该虚函数,由多态方式调用的时候动态绑定。
数据抽象:一种仅向用户暴露接口而把具体的实现细节隐藏起来的机制。
- 访问标签强制抽象
- 数据抽象的好处
- 安全。类的内部受到保护,不会因无意的用户级错误导致对象状态受损。
- 便于更新。类实现可能随着时间的推移而发生变化,以便应对不断变化的需求,或者应对那些要求不改变用户级代码的错误报告。
- 设计策略:抽象把代码分离为接口和实现。所以在设计组件时,必须保持接口独立于实现,这样,如果改变底层实现,接口也将保持不变。在这种情况下,不管任何程序使用接口,接口都不会受到影响,只需要将最新的实现重新编译即可。
数据封装:一种把数据和操作数据的函数捆绑在一起的机制
- 设计策略:通常情况下,我们都会设置类成员状态为私有(private),除非我们真的需要将其暴露,这样才能保证良好的封装性。
接口(抽象类)
- 目的:给其他类提供一个可以继承的适当的基类。抽象类不能被用于实例化对象,它只能作为接口使用。抽象类不能被用于实例化对象,它只能作为接口使用。
- 如果一个 ABC 的子类需要被实例化,则必须实现每个虚函数。可用于实例化对象的类被称为具体类。
- 设计策略(不理解):外部应用程序提供的功能(即公有函数)在抽象基类中是以纯虚函数的形式存在的。这些纯虚函数在相应的派生类中被实现。这个架构也使得新的应用程序可以很容易地被添加到系统中,即使是在系统被定义之后依然可以如此。
- 借口和抽象类的区别:
Tips:
- const 相比 #define 的优点:
- const 常量有数据类型,而 #define 没有,编译器可以对前者进行类型安全检查,而对后者只能进行字符替换,没有安全检查,并且在字符替换时候可能导致意想不到的错误。
- 有些集成化的调试工具可以对 const 常量进行调试,但是不能对宏常量进行调试。
如果文章对你有帮助,麻烦动动手指点赞、喜欢、支持一下咖啡猫,谢谢!