程序从写完之后到可以运行期间所要经历的过程:
1.预处理 2编译:按照该种语言的语法来检测程序是否存在语法问题,并且每个源文件编译完成后都会生成一个对应的obj目标文件(c语言编译器对函数名字的修饰规则:仅仅在函数名字前添加了一个下划线,C++编译器对函数名字的修饰规则:将参数类型的信息添加到最终的名字中) 3.汇编:翻译二进制格式的文件 4.链接:将多个目标文件拼接成一个可执行文件+地址问题(只编译源文件,不编译头文件—因为在源文件中包含的头文件已经被展开了)
关键字
c90 32个 c++98 63个
命名空间
在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。
定义
namespace N1
{
int a;
int Add(int left, int right)
{
return left + right;
}
}
注意:一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中(命名空间可以嵌套定义,同一工程下可以定义相同名字的命名空间)
使用
1.加命名空间名称及作用域限定符
int main()
{
printf("%d\n", N::a);
return 0;
}
2.使用using将命名空间中成员引入(此方法使用时全局作用域中不能含有相同的变量名)
using N::b;
int main()
{
printf("%d\n", N::a);
printf("%d\n", b);
return 0;
}
3.使用using namespace 命名空间名称引入
using namespce N;
int main()
{
printf("%d\n", N::a);
printf("%d\n", b);
Add(10, 20);
return 0;
}
打印全局变量
#include <stdio.h>
#include<windows.h>
int a = 10;
int main()
{
int a = 20;
printf("%d", ::a);
system("pause");
}
C++输入&输出
#include<iostream>
using namespace std;
int main()
{
int a;
double b;
char c;
cin>>a;
cin>>b>>c;
cout<<a<<endl;
cout<<b<<" "<<c<<endl;
return 0; }
<<是流插入运算符,>>是流提取运算符。
缺省值(默认参数)注意事项
- 半缺省参数必须从右往左依次来给出,不能间隔着给
- 缺省参数不能在函数声明和定义中同时出现
- 缺省值必须是常量或者全局变量
- C语言不支持(编译器不支持)
函数重载
定义
同一作用域中声明几个功能类似的同名函数,这些同名函数的 形参列表(参数个数 或 类型 或 顺序)必须不同
表现
重载时,编译器找到,找到就直接调用,如果找不到,编译器就会尝试进行隐式类型转换,转换之后如果有合适类型参数可供调用,就编译通过
extern “C”
将某些函数按照C的风格来编译,在函数前加extern “C”,意思是告诉编译器,将该函数按照C语言规则来编译
extern "C" int Add(int left, int right);
int main()
{
Add(1,2);
return 0; }
创建静态库
创建/使用
创建 创建相应的头文件和源文件,并生成解决方案。首先需要将.lib的静态库文件和.h的头文件拷贝到要使用的工程目录下.lib和exe放在同一个目录.h头文件和代码放在一个目录 使用 方法一: 方法二:
源文件.c如何让c/c++皆可依赖
在相应头文件中
引用
int a = 10;
int& ra = a;
printf("%p\n", &a);
printf("%p\n", &ra);
引用类型必须和引用实体是同种类型的
特性
- 引用在定义时必须初始化
- 一个变量可以有多个引用
- 引用一旦引用一个实体,再不能引用其他实体
常引用
const int& ra = a;
int& rb = 10;
应用场景
void Swap(int& left, int& right) {
int temp = left;
left = right;
right = temp; }
int& Count()
{
static int n = 0;
n++;
return n; }
效率:函数传参时:传地址和引用差不多,传值最慢。
引用和指针的区别
在底层实现方式上:指针和引用就是一样的,即引用在底层就是按照指针的方式来实现 概念说—>引用是一个别名,与其引用的实体共用同一份内存空 间,编译器不会给引用变量分配新的内存空间(实际有)
T&可以将其看成是T *const类型的指针 const T&可以将其看成是const T *const指针
底层
int main()
{
int a = 10;
int& ra = a;
ra = 20;
int* pa = &a;
*pa = 20;
return 0; }
汇编 在c++中const修饰的内容已经是一个常量了,而c语言中是一个不可被修改的变量
const int a=10;
int c[a];
解释:在cout<<a时c++替换成了10,而此时a已经成为了100,所以在监视和cout<<*pa输出100
宏
优缺点
优点: 1.增强代码的复用性。 2.提高性能。 缺点: 1.不方便调试宏。(因为预编译阶段进行了替换) 2.导致代码可读性差,可维护性差,容易误用。 3.没有类型安全的检查 。
可替换技术
- 常量定义 换用const
- 函数定义 换用内联函数
内联函数(重要)
inline是一种以空间换时间的做法,省去调用函数额开销(简易型)。所以代码很长或者有循环/递归的函数不适宜使用作为内联函数(声明和定义不能分开)。如果在其他文件使用内联函数,内联函数放到头文件中即可
#include <iostream>
using namespace std;
inline int add(int left,int right){
return left +right;
}
int main(){
int a=20;
int b=20;
int sum=add(a,b);
cout<<sum<<endl;
return 0;
}
有时候使用inline修饰的函数并没有按目标展开
1.debug版本下,编译器几乎不会对代码进行任何优化,优化了之后不方便调试了在debug版本下编译器一般不会将内联函数展开—展开之后就不能调试 想要查看的话
- inline是一个建议性的关键字
auto
早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量 C++11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得(auto作用:实际上是一个占位符,编译器编译代码时会推演变量的初始化表达式的类型,然后替换auto(必须初始化))。
#include<iostream>
#include<Windows.h>
using namespace std;
int a = 10;
int main()
{
int a = 10;
auto b = a;
auto c = 'a';
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
cout << typeid(a).name() << endl;
system("pause");
}
细节
- 1.用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
#include<iostream>
#include<Windows.h>
using namespace std;
int a = 10;
int main()
{
int x = 10;
auto a = &x;
auto* b = &x;
auto& c = x;
cout << typeid(a).name() << endl;
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
system("pause");
}
- 2.当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
auto a = 1, b = 2;
auto c = 3, d = 4.0;
auto不能推导的场景
- auto不能作为函数的参数
- auto不能直接用来声明数组
- 为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法
- auto在实际中最常见的优势用法就是跟以后会讲到的C++11提供的新式for循环,还有lambda表达式等进行配合使用。
基于范围的for循环(C++11)
int array[] = { 1, 2, 3, 4, 5 };
for(auto& e : array)
e *= 2;
for(auto e : array)
cout << e << " ";
使用条件
- for循环迭代的范围必须是确定的
- 迭代的对象要实现++和==的操作
空指针
C++98中的指针空值,NULL实际是一个宏,在传统的C头文件(stddef.h)中;在C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器默认情况下,将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void *)0
注意:
- 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的。
- 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。
- 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。
|