第1节 工程构成、语言特性、可移植性
一、语言特性
1、面向过程式程序设计:从上到下,一步一步解决问题;
2、基于对象的程序设计:把功能放在类中,通过定义对象来调用成员变量(函数);
3、面向对象的程序设计:继承性、多态性(父子方法同名时调用谁?)。
面向对象的程序设计优点:
① 易维护 ② 易扩展 ③ 模块化(限制访问可以保护数据安全)
二、工程文件构成
1、头文件:.h,.hpp
2、源文件:.c,.cpp,.cc(GNU),(MAC上).m,.mm
三、可移植性问题
1、(快)编译型语言:需要编译过程,编译成二进制文件(可执行文件),如c++;
2、(慢)解释型语言:文本方式存储,先解释,再运行,如lua。
第2节 命名空间简介、基本输入输出精解
一、命名空间
1、命名空间是为了防止名字冲突而引入的一种机制;
2、系统中可以定义多个命名空间,每个命名空间都有自己的名字(不可以同名);
3、命名空间的定义可以写在多个文件中。
4、定义:
//标准
namespace 命名空间名 { }
//例
namespace xzh
{
void output(){
printf("xzh\n");
}
}
使用:
//标准
命名空间名::实体名
//例
xzh::output();
5、定义后写上using namespace xzh; 就不用写 :: ,可以直接调用。
二、cin、cout精解
std::cout<<"xzh\n";
//cout(console output)
//cout是标准输出对象(与iostream相关)
1、cout与<<合用时会被重载,叫做输出运算符;
2、endl有刷新输出缓冲区(一段内存)的作用;
3、什么时候缓冲区的东西会显示在屏幕上?
a)缓冲区满了
b)执行到return了
c)调用了std::endl
d)系统不太繁忙时,会检查输出缓冲区内容,有新内容则输出(所以 \n 时能输出)
第3节 auto、头文件防卫、引用、常量
一、auto(变量的自动类型推断):发生在编译时,不会造成程序效率降低。
二、头文件防卫式声明(防止include头文件时的重定义)
#ifndef __HEAD1__H__
#define __HEAD1__H__
int g_globalh1 = 8;
//...
#endif // !__HEAD1__H__
//或者用
#pragma once
int g_globalh1 = 8;
//...
三、引用
1、为变量另起一个名字,别名与变量本身可以看做一个东西;
2、定义引用:不额外占用内存,定义时必须初始化(必须绑定到变量、对象上);
3、形参带&,值会传到外界!
四、常量
constexpt(c++11):编译时求值(提升性能),constexpr的函数要写得很简单。
第4节 范围for,动态内存分配,nullptr
一、范围for语句(c++11)
int a[3] = { 1,2,3 };
//用&x替代x可以省去拷贝动作,提高效率
for (auto &x : a) {
cout << x << endl;
}
//输出
//1
//2
//3
二、动态内存分配
1、存储位置
【c】程序区、静态存储区、动态存储区
【c++】五个区
(1)栈:一般函数内的局部变量(int a=0;),有编译器自动分配和释放;
(2)堆:程序员用malloc/new分配,用free/delete释放(若忘记释放,程序结束后系统回收,但有需要全年运行的程序!);
(3)全局/静态存储区:全局变量或静态变量(static);
(4)常量存储区:“xzh”
(5)程序代码区
2、栈和堆区别
(1)栈空间有限,分配速度跨快,程序员无法控制;
(2)堆:只要不超出实际物理内存,也在操作系统允许分配的最大内存以内,都可以分配,慢但是灵活。
3、使用方法
【c】malloc/free从堆中分配/释放内存(malloc=memory allocation,malloc和free是函数)
//标准
void *malloc(int NumBytes); //NumBytes为要分配的字节数
void *free(void *FirstByte);
//例
int *p = (int *)malloc(sizeof(4));
free(p);
【c++】new/delete从堆中分配/释放内存(new和delete是运算符或标识符)
//指针变量名 = new 类型标识符;
int *p1 = new int;
//指针变量名 = new 类型标识符(初始值);
int *p2 = new int(0);
//指针变量名 = new 类型标识符[内存单元个数];
int *p3 = new int[3];
//释放
delete p1;
delete p2;
delete[] p3;
【注意】
(1)delete后,指针指向的地址不变,指向的内容里的东西没有了!
(2)new成功一定要delete!
(3)不能重复调用delete!
(4)能用nullptr的地方不用null!
第5节 结构、权限修饰符、类简介
一、结构(c++比c中多了成员函数!)
形参变成引用,无需内存拷贝 VS 用指向结构体的指针做参数
struct student {
int number;
char name[20];
};
//加引用符号!
void func1(student &temp) {
temp.number = 70;
}
//传地址用指针接,用箭头
void func2(student *temp) {
temp->number = 30;
}
int main()
{
student student1;
student1.number = 10;
//字符数组初始化方法!
strcpy_s(student1.name, sizeof(student1.name), "xzh");
//调用此类函数前或更改student1值前必须初始化
func1(student1);
cout << student1.number << endl;
func2(&student1);
cout << student1.number << endl;
system("pause");
return 0;
}
//输出
//20
//30
二、public和private权限修饰符:private的只能被自己的成员函数调用!
三、结构和类区别
1、结构内成员变量和成员函数默认为public,类默认为private;
2、结构的继承默认为public,类默认是private。
四、类的组织(书写规范)
类的定义代码写在头文件中,头文件名可以跟类名相同,如student.h,类的具体实现代码卸载.cpp中,student.cpp。
第6节 函数新特性、内联函数、const详解
一、后置返回类型
auto func(int a) -> void; //声明
二、内联函数
1、函数定义前加inline;
2、函数体小但使用频繁的时候使用;
3、inline影响编译器,系统尝试用函数本体替换调用动作,int a = func(0); => int a = 4;;
4、inline只是开发者对编译器的建议,是否起作用取决于编译器的诊断功能;
5、优缺点:代码膨胀问题,所以函数体应尽可能小。
三、函数杂合用法总结
1、只要没调用函数,可以只声明,不定义;
2、一个普通函数只能定义一次,但可以声明多次;
※ 函数定义放.cpp,函数声明放.h
3、引用作形参可以避免值拷贝,效率高,c++用的多!
四、const char 星号在前、中、后的区别
1、const char *p //p指向目标中的内容不能通过p来修改(p++等指针移动可以)
2、char const *p //等价于1
3、char * const p = str //定义时必须初始化
//p一旦指向一个东西后,就不能指向其他了(与1、2相反)
4、const char * const p; //结合1、3
五、函数形参中带const:可以防止无意修改形参值导致实参也改变,实参类型也可以更灵活!
第7节 string类型介绍
一、简介(#include<string>)
二、定义和初始化:可以用字符数组初始string;
三、常用方法:s.c_str() 返回一个指向s字符串的指针常量,const char * p = s.c_str(); 利用p可以查看s在内存中的地址。
//例:字符串转大写
string s = "xzh";
for (auto &x : s)
x = toupper(x);
cout << s << endl;
第8节 vector类型介绍
一、简介:容器、集合、动态数组
vector相当于类模板,<int>相当于类模板实例化,vector<int &>不合法,因为引用是别名,不是对象。
二、常用方法:清空容器——res.clear()
第9节 迭代器精彩演绎、失效分析及弥补、实践
一、迭代器简介:指向容器元素的指针
二、定义
vector<int>::iterator iter;
三、操作
vector<int> iv = {100,200,300};
vector<int>::iterator iter1 = iv.begin(); //返回的迭代器指向iv[0]
vector<int>::iterator iter2 = iv.end(); //返回的迭代器指向末端元素的后边一个位置
//反向迭代器
vector<int>::reverse_iterator iter3 = iv.rbegin();
vector<int>::reverse_iterator iter4 = iv.rend();
※ begin() 和 end() 返回的都不是元素!
※ 反向迭代器遍历的时候虽然从后往前但还是iter++!
四、运算符
1、*iter必须指向容器内有效元素。
2、==、!= 判断的是指向的位置,元素相同不等。
五、const_iterator迭代器:指向的值不能改变,指向可以变,所以只能读不能写。
【c++11】cbegin()、cend() 返回的都是常量迭代器!
六、迭代器失效
遍历时改变容器大小(push)所引起,防止失效方法:
① 插入、删除元素后,break出for循环重新遍历 ② 用while循环,每次重新计算iv.end()
//正确清空容器方法
vector<int> iv = {100,200,300};
while(!iv.empty()){
auto iter = iv.begin();
iv.erase(iter); //移除iter位置元素,返回下一个位置
}
第10节 类型转换
一、隐式类型转换(系统自动进行的,如int a = 3 + 4.5;)
二、显示类型转换(强制类型转换)
//c语言风格
int k = 5%(int)3.2;
int p = 5%int(3.2);
【c++】通用形式:强制类型转换名 <目标类型> (要转换的东西);
1、static_cast:正常转换;子类对象转为父类对象;void* 与其他类型指针之间的转换。
2、dynamic_cast:运行时类别识别和检查;
3、const_cast:去除指针/引用的const属性;
4、reinterpret:重新解释,处理无关类型之间的转换;
常用于:整型和指针之间的转换和一种类型指针与另一种类型指针之间的转换。
三、总结
1、强制类型转换不建议使用,能够抑制编译器报错;
2、reinterpret危险,使用const_cast意味着设计缺陷。