枚举类型
-
类型定义格式 enum 枚举类型名 { 元素表 } ;
-
石头、剪子、布中的枚举类型 用户输入值的类型: enum p_r_s{ paper,rock, scissor, game, help, quit}; 比较结果类型: enum outcome { win,lose, tie};
-
枚举类型变量的定义 p_r_s select;
-
枚举类型变量的使用 赋值: select = paper; 比较: paper< rock 比较这两个值的内部表示枚举类型不能直接输入输出
-
枚举类型的内部表示 5 表示quit采用编码表示: 默认用0代表pape, 1代表rock,...,
-
指定编码值
- 希望从1而不是0开始编号,可以这样定义 enum p_r_s { paper = 1, rock, scissor, game, help, quit ] ;
- 可以从中间某一个开始重新指定,如 enum p_r_s { paper, rock = 5, scissor, game, help, quit } ;
cpp
#include <bits/stdc++.h>
using namespace std;
enum fruits { apple, banana, orange, grapes = 4, strawberry, pear };
enum students { math, chemistry, cs, physics, biology };
int main() {
fruits a = apple, b = orange, c = strawberry;
students d = math, e = physics;
cout << (int)a << ' ' << (int)b << endl;
cout << ((a == d) ? "Yes" : "No") << endl;
cout << ((c <= e) ? "Yes" : "No") << endl;
return 0;
}
头文件和接口文件以及实现文件
结构体
- 定义一个对象:
- 可以使用普通结构体定义一个对象
.
,有四种方式,分别是括号外紧跟加;
;括号外不加;
加语句;无名结构体;和typedef struct
; 下面是第二种创建实例
arduino
struct Student Stu;
- 或者使用结构体指针创建一个对象
->
访问,此时需要new
一下:
ini
Student *s = new Student(); // 或者Student *s = new Student;
- 对象的输入多种多样,需要构造函数帮忙:
- 构造函数初始化时,可以看成两个部分,一个是初始化
: data(a)
就是把输入的data = a
传给结构变量,一个是执行{},不需要加;
scss
//注意构造函数最后这里没有分号哦!
node() :x(), str(), data(){} //无参数的构造函数数组初始化时调用
node(int a, string b, char c) :data(a), str(b), x(c){}//有参构造
或者:
scss
MyTree(){}
MyTree(int val):left(NULL),right(NULL),val(val){}
传入参数的化就选择有参数的构造函数创建一个对象 ,但是传入的参数必须按顺序输入并赋值,如果缺少某个值,后面的结构体变量都无法赋值,此时我们可以在构造函数内给变量赋初值,这个我会。
c
//注意构造函数最后这里没有分号哦!
node(int a, string b, char c = '2') :data(a), str(b),{}//有参构造
- 类的嵌套请参考:
c++
struct Costs
{
double wholesale;
double retail;
};
struct Item
{
string partNum;
string description;
Costs pricing;
//嵌套了上方的结构
}widget;
widget.partnum = "123A";
widget.description = "iron widget";
widget.pricing.wholesale = 100.0;
widget.pricing.retail = 150.0;
模板类与模板函数
c++
类模板:template<class T1,T2>
class hello{
类模板的成员们。
此外还可以定义一个函数模板;
函数的输入参数也是模板的输入T1,T2;
}
由该类模板生成的类hello就叫做模板类。
生成一个实例化的类helloworld:
hello<int,int> helloworld;
helloworld . 成员就可以调用啦
泛型程序设计(generic programming)是一种算法在实现时不指定具体要操作的数据的类型的程序设计方法。 最成功的应用就是 C++ 的标准模板库(STL)。 C++ 中,模板分为函数模板和类模板两种。 也就是写函数的时候把它变成函数模板,写类时变成类模板。 思想就是:数据类型的参数化。
-
在C++中,数据的类型也可以通过参数来传递,在函数定义时可以不指明具体的数据类型,当发 生函数调用时,编译器可以根据传入的实参自动推断数据类型。
-
值(Value)和类型(Type)是数据的两个主要特征,它们在C++中都可以被参数化。!以往我们只会使用参数来代替一个数据具体的值,现在也可以代替一个数据类型了。此时,用于表示类型的参数叫做类型参数。使用 T、T1、T2、Type 等已经成为了一种惯例。
-
它所用到的数据的类型(包括返回值类型、形参类型、局部变量类型)可以不具体指定,而是用一个虚拟的类型来代替(实际上是用一个标识符来占位),等发生函数调用时再根据传入的实参来逆推出真正的类型。这个通用函数就称为函数模板(Function Template) 。
c++
//函数声明定义模板
template <typename 类型参数1 , typename 类型参数2 , ...> 返回值类型 没有分号是一个花括号
{ 函数名(形参列表){\
//在函数体中可以使用类型参数\
}
//声明函数模板
template<typename T> T max(T a, T b, T c);
//定义函数
template<typename T> //模板头,这里不能有分号!!
T max(T a, T b, T c){ //函数头
由于老版本中经常使用class来代替typename所以可能有些代码会用到这个class作为关键字。 和函数一样也可以提前声明,在使用以后定义。
类模板
c++
//类模板声明
template<typename 类型参数1 , typename 类型参数2 , ...> class 类名{\
//TODO:\
};
- 不同与模板函数一定需要定义参数的类型。
强/弱类型语言
- 强类型语言 在定义变量时需要显式地指明数据类型,并且一旦为变量指明了某种数据类型,该变量以后就不能赋予其他类型的数据了,除非经过强制类型转换或隐式类型转换。
c++
1. int a = 100; //不转换
1. a = 12.34; //隐式转换(直接舍去小数部分,得到12)
1. a = (int)"http://c.biancheng.net"; //强制转换(得到字符串的地址)
-
弱类型语言 定义变量时不需要显式地指明数据类型,编译器(解释器)会根据赋给变量的数据自动推导出类型,并且可以赋给变量不同类型的数据。 弱类型语言有 JavaScript、Python、PHP、Ruby、Shell、Perl
-
编译器(解释器)内部都有一个类型系统来维护变量的各种信息。\
- 强类型语言先编译后执行;编译型语言
- 弱类型语言一边编译一边执行;解释型语言
模板和数据类型存储直接相关,因为数据结构定义以后,存储的数据类型是多样的。因此需要模板函数。
虚函数与多态
本质是因为定义了一个基类指针但是指向了派生类对象
面向对象程序设计语言有封装、继承和多态三种机制,这三种机制能够有效提高程序的可读性、可扩充性和可重用性。
- 编译时的多态: 函数的重载(包括运算符的重载)、对重载函数的调用,在编译时就能根据实参确定应该调用哪个函数
- 运行时的多态: 继承、虚函数。
基类指针只能访问派生类的成员变量,但是不能访问派生类的成员函数。 派生类继承了基类的特性,但是使用普通的指针指向派生类对象,不能访问派生类的成员函数。
使用 <math xmlns="http://www.w3.org/1998/Math/MathML"> v i r t u a l virtual </math>virtual 关键字就是虚函数(visual function)
有了虚函数,基类指针 指向基类对象时就使用基类的成员(包括成员函数和成员变量),指向派生类对象时就使用派生类的成员。 换句话说,基类指针可以按照基类的方式来做事,也可以按照派生类的方式来做事,它有多种形态,或者说有多种表现方式,我们将这种现象称为多态(Polymorphism) 。
-
与其他指针的不同: 指针调用普通的成员函数时会根据指针的类型(通过哪个类定义的指针)来判断调用哪个类的成员函数
-
这里的指针: 虚函数是根据指针的指向来调用的,指针指向哪个类的对象就调用哪个类的虚函数。
面向对象编程:
也就是说,指针指向不同的对象就会执行不同的类成员函数等。多态就是基础特征。
C++提供多态的目的是:可以通过基类指针对所有派生类(包括直接派生和间接派生)的成员变量和成员函数进行"全方位"的访问,尤其是成员函数。 虚函数唯一用处就是构成多态。多态时一般是说指针。 对于具有复杂继承关系的大中型程序,多态可以增加其灵活性,让代码更具有表现力。 有了多态,只需要一个指针变量 p 就可以调用所有派生类的虚函数。
引用在本质上是通过指针的方式实现的- <math xmlns="http://www.w3.org/1998/Math/MathML"> c o n s t ∗ p const *p </math>const∗p
markdown
引用类似于**常量**,只能在定义的同时初始化。并且以后也要从一而终,不能再引用其他数据。
当基类的引用指代基类对象时,调用的是基类的成员,而指代派生类对象时,调用的是派生类的成员。结果是确定的。
new m_x(x) 不懂。
多态虚函数具体实现需要注意:
-
声明处加上virtual,定义不做要求。
-
在基类和派生类都定义了相同的函数名时,会发生遮蔽; 基类 People 和派生类 Student 都定义了成员函数 show(),它们的名字一样,会造成遮蔽。第 37 行代码中,stu 是 Student 类的对象,默认使用 Student 类的 show() 函数。 但是,基类 People 中的 show() 函数仍然可以访问,不过要加上类名和域解析符。 基类成员函数和派生类成员函数不会构成重载,如果派生类有同名函数,那么就会遮蔽基类中的所有同名函数。
markdown- 当发生了多态问题也就是**基类指针指向了派生类对象**
-
只将基类中的函数声明为虚函数,这样所有派生类中具有遮蔽关系的同名函数都将自动成为虚函数。
-
在基类中定义了虚函数时,如果派生类没有定义新的函数来遮蔽此函数,那么将使用基类的虚函数。
-
只有派生类的虚函数覆盖基类的虚函数函数原型相同) 才能构成多态(通过基类指针访问派生类函数)。
-
派生类不继承基类的构造函数。 -析构函数可以声明为虚函数,而且有时候必须要声明为虚函数
下面是构成多态的条件:\
- 必须存在继承关系;
- 继承关系中必须有同名的虚函数,并且它们是覆盖关系(函数原型相同)。
- 存在基类的指针,通过该指针调用虚函数。
delete:
释放内存块
delete p;
:node *p = new object;
- 内置类型比如数组;
delete[] a;
:int a[] = {1,2,3};
如果时删除一个类对象的内存只用delete可能会导致程序崩溃;我们需要把类对象中的所有指针都给delete;此时我们使用析构函数;
new:
分配初始化对象或者一个对象数组;而且返回一个指向对象或数组的头部元素的一个非零指针; 如果不能new
那么可能引发一个异常; 构造过程 首先new
一个类对象时,先给对象分配内存然后调用构造函数; delete以后先释放由new
分配的内存。然后记得把指针归零也就是p = NULL;
构造规定
- 使用
new
构造一个二维数组时,第一个维度可以是零,new以后返回一个唯一的指针; 但是这里的new
不能使用const
/volatile
一个是类声明一个是枚举声明; - 由于引用本质是指针,没有具体的对象,所以无法使用
new
总结写模板类时注意的细节:
-
class{}后面加上
;
-
templatetypename 比class好先进!
-
结构函数数使用方法:
- 可以在public中定义,因为一般结构函数可能需要向里面输入,然后赋给private里面的成员变量。成员变量和结构函数的输入变量最好不要使用一样的名字;
-
成员函数:
- 先声明,在定义类的里面一般是public,因为外界需要调用。声明如果没有同时定义的话,需要在结尾处添加
;
- 然后定义一个函数 需要采用下面的结构`type(函数返回值的类型) + 类的名字+ +::(重载符号) + 函数名字 +(输入变量){}
- const需要注意,声明和定义时需要用到相同的const;
- 先声明,在定义类的里面一般是public,因为外界需要调用。声明如果没有同时定义的话,需要在结尾处添加
-
析构函数: 比较特殊
~
+类的名称(){}- 因为析构函数的作用是需要把指针都删除所以需要把指针都变成NULL
-
struct和class都可以用来定义一个类: 其中class 默认都是private; struct 默认都是public;
-
类可以是嵌套的; 定义类里面的成员函数时,可以直接使用类的成员变量
-
类是会被覆盖或者是抽象类调用也就是基类派生出的多态需要使用
virtual
虚函数。 -
类函数或者类成员变量如果是private,也就是不需要用户主动访问就可以在类里面实现。不给用户使用,不会造成内存泄漏。!
整数的数据范围:
arduino
unsigned int 0~4294967295
int 2147483648~2147483647
unsigned long 0~4294967295
long 2147483648~2147483647
long long的最大值:9223372036854775807
long long的最小值:-9223372036854775808
unsigned long long的最大值:18446744073709551615
__int64的最大值:9223372036854775807
__int64的最小值:-9223372036854775808
unsigned __int64的最大值:18446744073709551615
typedef
表示定义一个类型
typedef int T
还可以表示数组,函数f()
变量类型等等; 参考链接
封装原则:隐藏对象的属性和实现细节,仅对外公开接口,并且控制访问级别 在OOP(面向对象)编程中,用类来实现上面的要求。用类实现封装,用封装来实现高内聚,低耦合 高聚合是说一个对象的功能都在内部搞定,紧紧地结合在一起 低耦合是说对象之间的依赖要松散,不要牵一发动全身 只有这样,当系统规模扩大时,才能比较方便
容器
vector
-
一个容器里面所有的元素都需要类型是一致的,而且容器可以存放各种类型。
-
容器受动态内存分配器管理。
-
vector的大小是动态的,元素是顺序存储的序列按照索引寻找,受动态内存管理器管理。
-
用法很多
arduinoswap(vector&) 还可以定义二维数组vector vector<int> & res; vector<int*> res;定义一个整型二维数组,因为加了一个*
-
size() ok!
-
length() ,not ok!(string ONLY!)
-
strlen,not ok!(ONLY string vector!)
-
参考length(),因为是长度,是无符号整型,因此需要转换位有符号,此处可能会出错。 (int) s.length()
queue
- 表示容器中的队列先进先出
- pop
- push
- front
- back
- size()
- empty()