从C到C++,初级编程者应该掌握的基本技能。
- C/C++基本语法
- 基础数据类型
- 类及对象
函数 在编程概念中起到中枢的作用,往下包含变量声明、语句 、表达式、返回值等,往上涉及函数调用、结构模块、功能方法等
- 函数头
- 函数体
函数头: 包括函数名和函数参数及返回值,
函数体: 在由花括号({})包含的程序语句构成
- 声明语句
- 赋值语句
- 函数调用
- 消息语句
- 返回语句
- 不允许嵌套定义
- 先声明,后使用
- 必须有返回值(void也可看作是一种)
- 一般将声明放置在头文件中,实现放在cpp中,声明和定义分离
- main函数可以省略return 0;其他int类型返回值的函数不能省略
- 返回类型为void的函数,内部实现时可省略“return;”
类是C语句中变量类型的扩展,并开放给程序员。程序员可以方便 的自定义不同类型,生成对象,初始化、赋值、发送消息等,完成 既定程序功能
- 成员属性
- 成员函数
用 类(class) 来描述自然界中某种类别的物体,它们有些共性:状态和技能。 例如:鸟 有羽毛、爪子、翅膀,会飞、叫、跑、吃、繁殖等。那么可以定义(生成)bird 类别的对象(类的实例)。
class bird {
public:
void fly();
void chirp();
void run();
private:
int color;
int paw;
int wing;
}有了bird这个类,要描述具体某个鸟,它是什么颜色、翅膀什么样的,怎么叫的,会不会跑 等等属性和动作,就比较方便了。如果要让它叫、跑,就分别给它发消息。
bird bd;
bd.chirp();
bd.run();成员函数应该遵从前面关于函数特性的规则。
在编程语言设计之初,就预先定义基础数据类型。它们是用来表述世界的基本状态。一般程序语言 的基本数据类型包括:整形、浮点型、字符串。一般还提供组合数据类型:数组、 结构、枚举、记录(有点语言叫Record、Map、字典)等。
每一个表达式、每个变量、每个函数调用都有数据类型(void是一种特例)。编译器在做 语义检查时,主要是检查赋值语句左右两边的表达式类型是否匹配或满足隐式转换。 例如:把字符串对象赋值给整形变量,就会报错。
- 整型
- 浮点型
- 字符串
- 布尔型
整型,是以实数为基础,它是可数的,能够排序。C/C++将整型还细分多个子类型。
它的字面值如“3”、“5”、“-9”,还可在尾部添加u、l、ll字母等表示子类型。
浮点型,带小数点的数字,它的内部表示方式与整型不同,表示范围比较大,不可数。默认是
double类,字面值尾部添加f,表示float类型。
字符串型,表示一种符号语义,区别其他符号串。
布尔型,在逻辑里面代表“是/否”,它们与整型、浮点型和字符型都不同。
以基本数据类型为原子构建更多元的数据类型,描述更复杂的真实世界对象,包括数组、结构、 枚举、共用体,还包括字符串和指针。它们都是在基本数据类型的基础上创建的。
// 声明一个int数组,它包含三个int数据,同时初始化它们
int arr [3] = {12, 365, 24};
// 上面的大括号内包含多个元素并通过赋值等号给数组赋值,只有在初始化时可用
// 下面的代码编译通不过
float f_arr[3];
f_arr[3] = { 3.14, 0.618, 2.718};
结构体内包含字符指针时,它的对象之间如何赋值操作?浅拷贝or深拷贝
指针也是复合数据类型,如何理解?
指针是变量,它的内容是另一个数据对象的地址。那么它的类型不就是“指针”类型吗? 为何要说它是复合数据类型,和谁复合呢?计算机中用来表示数据对象的地址,是指向数 据对象在内存中所占据的空间的第一个字节的地址。当控制器要读取内存值的时候,还要 知道读余下几个字节,才能一起构成数据对象,以及如何解释它们。
所以,指针不能单独作为数据类型,还要加上它指向对象的数据类型,变成比如整数指针、 浮点数指针,两个整型输入作为参数,无返回值的函数指针...
- 基本类型指针
- 数组指针
- 函数指针
int a = 3; // 整型变量
int* p_int = &a; // 整型指针
/* 假设在32位机上
p_int数据对象存的是a这个变量的地址,占四个字节。同时要明白,a也是占四个字节
但是a的地址其实是它的第一个字节的地址。
*/其他基本数据类型情况类似,char指针,包括函数指针,也是函数块数据对象所占内存的第一个 字节的地址,编译器跟踪函数的其他信息,这样后续在调用时,也能进行正确解释数据的语义
这个概念要与指针数组区分开,其实指针数组没有什么特别的,它本质是个数组,元素是某个 类型的指针而已。表示方法也和其他类型的数组没有太大差别。涉及数组指针时,比较容易出错。
int a [4]; // 数组名是指向数组中第一个元素的指针
int* pa = a;
int** ppa = &a; // 对数组名求地址,表示这个数组的地址,那么ppa就是指向数组的地址
// 也即数组指针
函数名就是指向函数的指针,它的值就是函数对象所占内存的第一个字节的地址。 编译器在解释它的时候,结合它的内容,当做代码执行,所以它的语义结果是 “接受输入 -> 执行计算 -> 返回结果”,是动态的过程,而不像通常的数据对象 表示静止的状态。
必须有值,有类型。加上分号就变成语句了。 表达式是递归定义的,由基本运算符、变量、或由其他子表达式经过关系、逻辑 运算符组合而成,可以求值,它最终的“值”就是它的语义。
这是C++新引入的数据类型,是对指针变量的延伸,但是使用方式和普通变量 类似,最常使用场景是作为函数形参。当函数调用时,传入普通变量,由传值 变为传引用,在函数内部将不再新建临时变量,而是直接获取实参的内容。
1.面向对象概念
2.模板类
C++兼容C,基本的数据类、函数声明和定义等基础知识和C语言是相通的, 一个合法的C语言程序可以通过C++的编译并运行。但是,C++在C的基础上 扩展了类以及模板编程和函数式编程概念。
提供一种机制,允许程序员在基础类型(int, float, double ,char, bool, 指针,数组, 结构等)之上,自定义类型。
C++内部提供的基础类型,隐含定义了与之对应的方法,如int、float等有 算术运算、bool类型有逻辑运算等;还可以定义处理它们的各种函数。但是 当程序变庞大之后,管理这些基础类型变量和函数变得很困难。通过自定义类, 对象内部包含了相应的成员函数,从而减轻管理大型程序的负担。
类,极大的提高了编程的抽象能力。
由类实例化具体的对象,包含了成员变量和成员函数。成员变量是各实例化类对象 私有的,而成员函数在各对象之间的共用。一旦定了类,它的对象的私有变量可变, 行为是确定的。
子类从父类继承了全部的成员变量和成员函数,还可以添加自有变量和函数,或修改 父类的行为(成员函数内容),但它还是属于父类的一种,进化了自有部分,原来的 成员变量和函数依旧有效。
某个类中,含义另一个类的对象作为它的成员变量,叫做"包含",常用的例子是,汽 车有一个引擎,但是汽车不是引擎。但是它可以利用引擎的功能,使汽车行驶。 可以通过在汽车的公开接口中,暴露引擎提供的接口而实现对引擎的封装。
子类继承父类,同时希望表现出不同实现方式,那么可以将父类的相应成员函数 设置为虚函数,在子类中对该函数override,那么将子类对象的地址赋给父类指针 时,通过该指针调用虚函数时,就能调用子类的实现,表现出多态。多态的背后, 是通过虚函数表实现,简单说就是每个含义虚函数的类都有一个虚函数表,该表的每 个元素为指向它含义的虚函数的实现,而类对象隐含一个指向对应所属类的虚函数表 的指针。在通过指向父类的指针调用虚函数时,通过赋值它的对象的隐含地址,找到 这个虚函数表,循环查找相应的虚函数实现,然后执行。这发生在运行阶段,所以叫 "动态多态"。
在定义类时,通过声明某函数为类的友元函数,从而赋予了该函数访问类对象的私有 成员变量的权限。由于友元函数的声明是在声明类中实现的,与面向对象的封装 特性并不矛盾。