C++基础
命名空间
-
命名空间可以定义变量和函数
-
命名空间可以嵌套
-
使用
1.不展开
namespace N { int a=10; } int main() { printf("%d",N::a); }
2.单独展开
using N::a; int main() { printf("%d",a); }
3.整个展开
using namespace N; int main() { printf("%d",a); }
#include<iostream>
using namespace std;//C++中所有东西都在namespace中
int main()
{
cout<<"hello world"<<endl;
std::cout<<"hello world"<<std::endl;//单独展开(同上讲解)
return 0;
}
【std日常联系,图方便,全展开】
【std项目当中,可展开部分】
缺省参数
#include<iostream>
using namespace std;
void Func(int a=0)//缺省参数,若无传参,即用a=0(备胎)
{
cout<<a<<endl;
}
int main()
{
Func(10);//打印10
Func();//答应0;
return 0;
}
- 缺省参数-------备胎参数
全缺省(缺省全部参数)
void Func(int a=1,int b=2,int c=3)
{
cout<<"a="<<a<<endl;
cout<<"b="<<b<<endl;
cout<<"c="<<c<<endl;
}
int main()
{
Func();
Func(4);
Func(4,5);
Func(4,5,6);
}
半缺省(缺省部分参数)必须从右往左连续缺省
(调用从左往右依次调用)
void Func(int a,int b=2,int c=3)
{
cout<<"a="<<a<<endl;
cout<<"b="<<b<<endl;
cout<<"c="<<c<<endl;
}
int main()
{
//Func();//a无参数,不可取
Func(4);
Func(4,5);
Func(4,5,6);
//Func(1,,3);//不可
//调用从左往右依次调用
}
函数重载
一个函数可能会有多个意义,或多种调用方式(一词多义)
include<iostream>
using namespace std;
int Add(int a,int b)
{
return a+b;
}
int Add(double a,double b)
{
return a+b;
}
int Add(long a,long b)
{
return a+b;
}
int main()
{
return 0;
}
函数名相同,参数不同(返回值不同不构成重载int Func()–void Func() )
-
类型不同
Func(int a,int b) Func(double a,double b)
-
个数不同
Func(int a,int b) Func(int a) Func()
-
顺序不同
Func(double a,int b) Func(int a,double b)
返回值没有要求
调用时自动识别
面试二问
- 什么是函数重载
- C++是如何支持函数重载的?C语言为什么不支持?
list.h list.c test.c
预处理 -->展开头文件,宏替换,去注释,条件编译
list.i test.i
编译 -->处理语法错误,将代码转化为汇编语言
list.h test.h
汇编 -->将生成的汇编代码转化为二进制的机器指令
list.o test.o
链接 --> 将多个源文件链接起来
test.c void list_push_back(int x); void add(int i,int j); int main() { list_push_back(1); return 0; } ->test.o call list_push_back(?) //只有声明,没有定义,没有地址 //链接时,这里的问号表明在编译时只有声明,没有定义,所以无法找到他的地址,表示链接时,到其他目标文件符号表中去找到这个函数的地址 //只有声明,没有定义,会出现链接错误 符号表: main:0x31141321
list.c void list_push_back(int x); void add(int i,int j); void list_push_back(int x) { printf("%d\n",x); } void add(int i,int j) {} ->list.o list_push_back() { ..... } 符号表: list_push_back:0x31144332 add:0x31144332
编译时函数名跟参数关联起来(Z3是前缀)
extern “C”
C++实现 编译成动态库或者静态库
void*tcmalloc(size_t n)
C++ 程序调用可以 C程序调用也许不可以
c++
call tcmalloc(?)
c
call tcmalloc(?)
要求C和C++程序都可以使用C++编译成的动态库或静态库
extern "C" void* tcmalloc(size_t n)
//按c的修饰规则去调用
引用
#include<iostream>
using namespace std;
int main()
{
int a=1;
int &ra=a;//ra是a的引用,给a起了一个别名ra
}
- 共用一块空间,不开辟新空间
- 必须在定义的时候进行初始化(别名)
- 引用只能引用一个实体
#include<iostream>
using namespace std;
int main()
{
const int a=1;
int &ra=a;//权限放大,不可取
}
- 权限可以放大,不可以缩小
#include<iostream>
using namespace std;
int main()
{
int a=1;
double b=a//隐式类型转换,转换的时候会产生一个临时变量,临时变量具有常性(相当于const修饰)
double &ra=a;//不可以
const double &ra=a;//可以
}
-
赋值之间没有权限变大或缩小的关系,引用才有
-
如果返回变量是一个局部变量,引用返回时是不安全的
总结:一个函数要使用引用返回,返回变量出了作用域还存在,就可以使用引用返回,否则就不安全(全局变量,静态变量适合引用返回)
那么函数适应引用返回的好处是什么
- 少创建一个临时变量,提高程序运行效率
- 待定,我相信你会回来的
引用的目的
- 做输出型参数
- 提高传递效率
#include<iostream>
using namespace std;
int main()
{
int a=10;
int &b=a;
int *p=&a;
return 0;
}
指针与引用的区别
- 在概念上b就是a的别名,不开辟新的空间,就是一个别名,在底层实现上,是用指针的方法去实现的,指针在概念上是地址
- 引用必须初始化,指针不用(建议给NULL)
- 引用引用一个实体后,不能引用其他实体,指针可以在任何时候指向任何一个同类型实体
- 没有NULL引用,但有NULL指针
- 在sizeof中含义不同,引用结果为引用类型的大小,指针是地址空间所占的字节数
- 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
- 有多级指针,但没有多级引用
- 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
- 引用比指针使用起来安全
内联函数
频繁调用函数(调用函数需要调用栈帧,是有消耗的),怎么解决
-
C语言使用宏函数(不能调试)
-
C++使用内联函数(调用函数时展开,没有函数栈帧的开销)
inline void Swap(int &x1,int &x2) { int tem=x1; x1=x2; x2=tem; }
-
以空间换时间
-
一般内敛适用于小函数,小于20行
-
特性
- inline是一种以空间换时间的做法,省去调用函数开销
- inline对于编译器来说只是一个建议,编译器会自动优化
- inline不建议声明定义分离,(内联函数没有地址)分离会导致链接错误,因为inline被展开后就没有函数地址了,链接就会找不到
C++中宏的替代
define N 10
const int N=10;
宏函数---->inling函数替代
宏的优缺点
优点
- 增强代码的复用性
- 提高性能
缺点
- 不方便调试
- 代码可读性差,可维护性差,容易误用
- 没有类型安全的检查
auto关键字(C++11)
int main()
{
int a=0;
auto b=a;//b的类型是由a的类型推导的
cout<<typeid(a).name()<<endl;
cout<<typeid(b).name()<<endl;
return 0;
}
-
auto不能做参数
-
auto不能做数组
基于范围的for循环
int main()
{
int arr[]={1,2,3,4,5};
//数据×2,打印
//C语言
for(int i=0;i<5;++i);
{
arr[i]*=2;
cout<<arr[i]<<" ";
}
//C++11->范围for(语法糖)
for(auto &e:arr)
{
e*=2;
cout<<e<<" ";
}
}
int main()
{
//C
int *p1=NULL;
//C++推荐
int *p2=nullptr;
//原因:C++中NULL就是0
}