c89中没有缺省参数这个定义
c99之后有
现在都有c11
C和C++区别
1.带有默认值的函数(缺省)
从左向右 形参默认值
//给默认值的时候只能从右向左给,不可写成sum(int a=10,int b)
//函数声明与定义可以给一次默认值,但不可以重复定义
// intsum(int a,int b=20);
int sum(int a=10,int b); 这个也可以,但是顺序不能颠倒 ,要遵循从右向左赋予参数
2.inline 内联函数
【一般函数调用的开销>函数执行的开销 将其写成内联函数,一般写在头文件里面】
*UDN* ???对符号的引用
.test 是对符号的定义,在链接的第一阶段,所有的.obj文件的段都
会进行合并调整段的大小以及起始地址的偏移量,然后合并符号表进行符号解析,
让所有符号引用的地方都要定位到符号的定义处,具有唯一性,定位好之后分配
内存的虚拟地址;第二步进行符号的重定位
***与宏的区别
内联函数 在函数的调用点,将函数的代码全部展开 (编译过程)
宏是在预编译阶段 处理的 == 字符串替换
内联可以称为一种更安全的宏(会进行类型检查 在编译阶段) 所以说内联函数可以调试
***内联函数 和 普通函数的区别???
内联函数::没有标准的函数栈帧的开辟和回退
普通函数
如果 调用函数的开销》函数执行的开销 建议设置成内联函数
// 所以 有些函数比较短的话 可以将它处理成内联函数
***内联函数 和 static函数的区别???
相同点:当前文件可见,作用域一样,都有正常的栈帧的开辟与回退
区别: 内联:: 在调用时,编译器会在调用处将其汇编代码展开编译而不为这个函数生成独立的汇编代码,无函数符号产生
静态:: 栈帧的开辟与回退与普通函数是一样的,也就是存在函数栈帧的开辟与回退,会耗费系统资源。
内联函数与普通函数的区别
普通函数在编译的过程中由编译器将函数体放入代码段,在调用函数过程中先进行参数的压栈,然后根据函数的调用地址调用函数,并执行,函数返回后执行出栈操作,这样就会有一个调用的过程,会有时间的消耗。内联函数可以避免这样的消耗,一个函数申明为内联函数,在编译的过程中,编译器会将函数体代码插入函数调用处,这样虽然会增加代码段的空间,但是可以避免时间上的消耗,提高了效率。
成员函数与静态函数的区别
1、所有函数代码都在程序编译连接时放在一块,称为代码区,无论是静态还是非静态函数都一样,不存在 "构造一个类的对象(第一次构造对象)时,就会给成员函数(非静态成员函数)分配代码区空间 ",而是程序加载时,所有的代码已在内存空间存在. 只有函数中用到的局部变量才是函数调用时分配空间.
2、静态成员函数和成员函数之间根本的区别是:静态成员函数实际上是一个全局函数,不依赖一个类的对象.函数定义时之所以把静态成员函数定义在类中,是一种弱逻辑. 普通成员函数依赖一个类的对象,也就是它有this指针,必须指向一个类的对象.
3、建立类的对象时只是给成员变量分配空间,析构时也只回收这些空间,代码段里的函数以及静态函数和变量都是在程序结束后回收。
inline 只在release版本起作用
gcc g++ -o1 -o2 -o3 优化级别
3.函数的重载
c语言的函数产生符号是根据函数名称
c++产生的函数产生的符号是 函数名称+形参的类型+形参的个数
3. 函数的重载
C语言中 函数产生的符号 是由函数名称决定的
C++语言 函数产生符号 函数名称+形参的类型+形参的个数
1.函数名相同,参数列表不同 不能仅通过返回值不同
2.必须处于同一个作用域之内,否则不算重载
3.。。。。。。。。。。。
面试:: 静多态与动多态
静多态:函数的重载 模版
动多态:继承里面的多态
符号类型转换
double <---------float
↑
unsigned
↑
long
↑
int <-------- short char
注: 横向箭头: 无条件转换
纵向箭头: 当出现两个纵向的数据类型的时候,把下面的转换成上面的
面试????静态连接和动态连接的区别
静态链接: 在编译链接时直接将需要执行的代码拷贝到调用处,
优点是:在程序运行时不需要带着库一起执行
缺点是:占用磁盘空间
动态链接: 在编译时不拷贝可执行代码,通过记录一系列符号和参 数,在程序运行或加载时将这些信息传递给操作系统。
优点是:多个程序可共享同一段代码,不需多拷贝占用磁盘空间
缺点是:运行时加载费时,可能会影响程序的前期执行性能
静态链接库 *.a(linux) *.lib(windows) 静态链接时可执行文件未生成
动态连接库 *.so(linux) *.dll(windows) 程序运行时链接
extern "C"{代码} 转换C语言规则 代码
/*
c和C++之间的相互调用
c++->c
static int sum(int a,int b) // local 局部的
{
returna+b;
}
C文件中的函数都是用C语言的规则生成的 符号表不一样
c->c++
C++的宏开关
#ifdef _cpluslplus
extern "C"
{
#endif
code....
#ifdef _cplusplus
}
#endif
*/
#if 0
#include<iostream>
using namespace std;
bool compare(int a,int b) //compare_int_int
{
cout<<"compare(int,int)"<<endl; // <<"\n" endl==最后接一个“\n”
returna>b;
}
bool compare(double a,double b)
{
cout<<"compare(double,double)"<<endl;
returna>b;
}
bool compare(float a,float b) //
{
cout<<"compare(float,float)"<<endl;
returna>b;
}
bool compare(char * a,char * b)
{
cout<<"compare(char*,char * )"<<endl;
returnstrcmp(a,b)>0;
}
int main(int argc, char * argv[])
{
boolcompare(int a,int b);
compare(10,20);
compare(10.5f,20.4f);//???
//compare("hello","world");
return0;
}
#endif
/*
面试????静态连接和动态连接的区别
静态链接: 在编译链接时直接将需要执行的代码拷贝到调用处,
优点是:在程序运行时不需要带着库一起执行
缺点是:占用磁盘空间
动态链接: 在编译时不拷贝可执行代码,通过记录一系列符号和参数,在程序运行或加载时将这些信息传递给操作系统。
优点是:多个程序可共享同一段代码,不需多拷贝占用磁盘空间
缺点是:运行时加载费时,可能会影响程序的前期执行性能
静态链接库 *.a(linux) *.lib(windows) 静态链接时可执行文件未生成
动态连接库 *.so(linux) *.dll(windows) 程序运行时链接
extern "C"{代码} 转换C语言规则 代码
*/
/*
4. const 量-》 不能被修改的量
****C语言中的const****
·不是必须要被初始化的变量
·用const修改的量叫常变量 不是常量 绝对的常量是 立即数 比如 10 20 30
·const 修饰的常变量和普通变量的唯一区别:常变量定义以后,不能作左值
·常变量和普通变量的编译方式是一模一样的
常变量:就是在初始编译阶段不能确定其初始值的常量,意思就是初始值可以改变
如intb=x; x可以为任何数
const int a=b;
**********************
*****C++中的const*****
·必须初始化,和编译规则有关
·const修饰的量 =======常量 和常量的规则一样
·(cosnt 的编译规则, 所有使用常量名字的地方全部替换成变量的初始值)
·当C++中的常量 引用一个编译阶段不明确的值的时候 会变成和C语言一样的 常变量
·const 生成的量是局部的,要想全文件共享,在定义处 前面加extern
·与static一样 都是仅当前文件可见
//无法解析的外部符号 “int const char ”(?data@@3HB)
**********************
********const 与引用的结合 常引用*********
int b=10;
const int &a=b; (&a 需要开辟四个字节的内存来保存b的地址)
*****************************************
********const 与指针的结合*************
公式:
constint* -> int* //err
constint** -> int** //err
int**-> const int** //err
int*-> const int*& const int *&p=q;//err [看变量类型的时候不看引用]
***************************************
内置类型产生的临时量都是常量,不可更改
自定义类型产生的临时量都是变量,不可以更改
**************函数的返回值************
<= 4个字节 寄存器
if >4返回值大小<=8 通过两个寄存器带出来的eax edx
>8 产生临时量
不能返回局部变量的地址或者引用,因为函数结束后 局部变量的地址会被摧毁
*************************************
*/
//extern const int data;
/*
5.引用
面试::
floata=10.5;
intb1=(int)a; //类型强转
intb2=(int)&a; //& 取地址
intb3=(int &)a; //引用
(1).定义一个引用变量会开辟内存
访问引用变量的时候,底层就是指针的解引用
编译通过条件:
1.必须初始化 int&a;
2.初始化的值必须要能取地址 error: int&a=10;
3.应用不能被改变 int &a=b; &a=c;
4.访问应用变量,永远访问的是它所引用的内存
在C++中 引用比指针安全
*/
#if 0
int main()
{
inta=10;
int&b=a; //== int *b=&a;
int*p=&a;
intarray[10]={0};
int(*q)[10]=&array; //定义指针指向数组
int(&q)[10]=array; //引用数组
b=20;
*p=20;
return0;
}
#endif
/*
7. const 和 一级指针的结合
规则: const修饰的是距离它最近的类型
cosntint* -> int* error
int*-> const int* ok
const int *p; // 修饰int类型 *p表达式; P可以更改,但是不可以给指针解引用改值
int const *p; // 修饰int类型 *p表达式; 同上
int *const p; // 修饰int *类型 p表达式; P不能被赋值,可以给*p赋值
const int *const p; // 修饰 *p 修饰 int * *p与p 都不可以更改,都成为常量,必须初始化
以上四种为常量的只有最后两个
*/
#include<iostream>
#include<typeinfo>//可以打印类型的头文件
//7
#if 0
int main()
{
inta=10;
constint b=20;
a=b;
//b=a;//error 常量不可以做为左值
//直接 简介 常量的指针或者引用泄露出去
constint a=10;
int*p=&a; //const int* 整型常量的地址 此时a的值泄露出去
//上面这种情况 有几率修改a的值,不安全
const int a=10;
constint *p=&a;//cosnt int* *p=40; p=
inta=10;
constint *p=&a; //const int* <- int *
int*q=p; //*q=20; int * <- const int*
int *const q =&a; //cosnt 如果没有修饰 */&
return0;
}
#endif
//8 动态内存开辟
/*
malloc
free
new -> 调用的malloc 初始化(内置类型,自定义类型 调用构造函数)
delete
*/
int main()
{
//int*p=(int *)malloc(sizeof(int));
//free(p);
//int*p= new int(10);// 给予初始化值 10
//deletep;
//int*p=(int *)malloc(sizeof(int )*100);//开辟数组型内存
//free(p);
//int*p=new int[100];
//delete[]p; //释放内存要声明p是个数组
//3x4 三行四列的动态数组开辟
//ok
//int**p=new int*[3];
//for(inti=0;i<3;++i)
//{
// p[i] = new int[4];
//}
//for(inti=0;i<3;++i)
//{
// delete []p[i];
//}
//delete[]p;
//err
//int **p=new int[3][4];
//new在开辟内存失败的时候 会抛出 throw bad_alloc("");
//new有四种
int*p = new int(10); //默认版本的new 抛出异常
//int*p = new (nothrow) int(10); //第二个版本的new,不抛出异常,用NULL来判断p是否异常
/*if(p==NULL) //err 适合第二种版本 ,不抛出异常的
{
return-1;
}*/
try // 默认的new 判断p是否为空
{
int*p=new int(10);
}
catch(constbad_alloc &err)
{
}
//new有内存的开辟和初始化
//constint *p=new const int(4);// 第三种 在堆上开辟常量
//constint *q=new const int[10];// 两者皆无法赋值 ,因为是堆上的常量
//第四种 定位new placement new 不会真真正正的开辟内存
//charbuffer[1024]={0};
//char*p =new (buffer) char[100];
//int *p = new int(10);
//int*p = new int;
//*p=10;
//int*p=new int;
int*p=(int *)operator new(sizeof(int));
p= new (p) int(10);// 在已经开辟的p上面进行赋值,没有开辟内存,只是进行初始化