重载:
1.在同一作用域中,函数名相同,参数表不同的函数,构成重载关系
-void foo(void);
void foo(int n);
void foo(int* p);
char const* foo(int n,double d);
char const* foo(double d,int n);
2.重载与返回类型无关与参数名也无关,相同类型的引用与非引用不构成重载
-int void(void);//
void foo(int&r);
char const* foo(int d ,double n) 全错
3.调用函数时,根据实参与形参的类型匹配情况,选择一个确定的重载版本,这个过程称为重载解析
-void foo(void);
void foo(int n);
void foo(int* n);
int foo(double d);
char const* foo(int n,double d);
chat const* foo(double n,int d);
-int n;double d;
foo();foo(n);foo(&n);
foo(d);foo(n,d);foo(d,n);
4.函数指针的类型决定其匹配的重载版本
5.只有在同一作用域中的同名函数才涉及重载问题,不同作用域中的同名函数遵循名字隐藏原则
-void foo(void);
namespace ns1{
void foo(int a);
}
namespace ns2{
void foo(int a,int b);
void bar(void){
foo(10,20);
}
void hum(void) {foo(30);}
}
void fun(void){foo();}
这个就是不在同一个作用域当中;
c++换名
重载是通过c++换名实现的
换名机制限制了c和c++模块之间的交叉引用
extern"C"
通过extern"C"可以要求c++编译器按照c方式处理函数接口,即不做换名,当然也就无法重载
-c调c++,在c++中
exter "C"int add(int x,int y);
extern"C"{
int add(int x,int y);
int sub(int x,int y);
}
-c++调在c,在c++中
extern"C"{
#include"chead.h"
}
缺省参数:
可以为函数的参数指定缺省值,调用该函数时若未指定实参,则与该实参相对应的形参取缺省值
void foo(int a,int b=456);
foo(100);//编译为foo(100,456);
*如果函数的某一个参数具有缺省值,那么该参数后面所有参数必须都具有缺省值
函数的缺省参数是在编译阶段解决的,因此只能用常量,常量表达式或者全局变量等非局部化值作为缺省参数
int g = 123;void foo(int a =g,int b= 400+56);
void foo(int a,int b=a);//错误
如果需要将函数的声明和定义分开,那么函数参数的缺省值只能出现在函数的声明部分
缺省参数容易跟重载产生冲突,产生歧义
内联: 内联就是用函数已被编译好的二进制代码,替换对该函数的调用指令
内联在保证函数特性的同时,避免了函数调用的开销
内联通过牺牲代码空间,赢得了运行时间
隐式内联和显示内联
内联通常被视为一种编译优化策略
若函数在类或者结构体内部直接定义,则函数被自动优化为内联函数,谓之隐式内联
-struct User{
void who(void){}
};
若在函数定义前面,1加上inline关键字,可以显式告诉编译器,该函数被希望优化为内联函数,这叫显式内联
-inline void foo(void){...}
内联的适用条件
1.内联会使可执行文件的体积和进程代码的内存变大,因此只有频繁调用的简单函数才适合内联
2.稀少被调用的复杂函数,调用开销远小于执行开销,由内联而获得的时间性能的改善,不足以抵消空间性能的损失,故不适合内联
3.inline关键字仅仅表示一种对函数实施内联优化的期望,但该函数是否真的会被处理为内联,还要由编译器的优化策略决定
4.带有递归调用或动态绑定特性的函数,无法实施内联,编译器会忽略其声明部分的inline关键字
动态内存分配
new/delete操作符
.c++提供了new和delete操作符,分别用于动态内存的分配和释放
-int* p = new int;
delete p;
.c++的new操作符允许在动态分配内存时对其做初始化
-int* p = new int;
-int* p = new int();
-int* p = new int(100);
数组的分配与释放
以数组的方式new的也要以数组方式delete
- int* p = new int[4]{10,20,30,40};
delete[] p;
某些c++实现,用new操作符动态分配数组时,会在数组首元素前面多分配4/8个字节,用以存放数组的长度
new操作符所返回的地址是数组首元素的地址,而非所分配内存的起始地址
如果将new操作符返回的地址直接交给delete操作符,将导致无效指针(invalidate pointer)异常
delete[]操作符会将交给它的地址向低地址地址方向偏移4/8个字节,避免了无效指针异常的发生
重析构
不能通过delete操作符释放已经释放过的内存
-int* p = new int;
delete p;
delete p; //核心转储
-标准库检测到重析构(double free)异常后将进程杀死,并转储进程映像
delete野指针后果未定义,delete空指针安全
-int* p = new int;
delete p;
p = NULL;
delete p; //什么也不做
内存分配失败
内存非配失败,new操作符抛出bad_alloc异常
- char* p = (char*)malloc(0xFFFFFFFF);
if(p == NULL){
cerr<<"内存分配失败!"<<endl;
exit(-1);
}
- try{
char* p = new char[0xFFFFFFFF];
}
catch(bad_alloc&ex){
cerr<<"内存分配失败!"<<endl;
exit(-1);s
}
malloc 内存分配错误的时候会返回空指针,用new出现错误尽量用异常抛出
引用
1.声明一个标识符为引用,即表示该标识符可作为另一个有名或无名对象的别名
2.在c++中,无名对象通常都被处理为右值,只能通过带有常属性的引用引用之;
int a=10;
int& b= a,int&c = b;
++c;
cout<<a<<endl; //11
int const& d=c;
++d; //错误 error
3.引用必须在定义的时候进行初始化,不允许先定义再赋值
-int a= 10;
int& b=a; //ok
-int a=10;
int& b;//error
b=a;
堆区栈区的访问速度是没什么大的区别的.
归纳:
一.重载
1.重载的定义:同一个作用域,函数名相同,参数表不同,这样的函数构成重载关系
2.重载解析: 类型匹配,类型安全,最小工作量.
3.函数指针: 根据指针的类型(中参数表信息)选择重载版本.
4.extern "C" 关键字: 抑制c++编译器的换名.
二.缺省参数
1.可以为函数的参数指定缺省值,如果调用该函数不指定部分或全部实参,编译器会对应参数的缺省值作为实参
2.函数的缺省参数必须靠后
3.参数的缺省值,不能用局部变量
4.函数的缺省参数只能出现在函数的声明部分
5.使用缺省参数时避免与重载发生冲突..
int a;
a 变量
int a[4];数组
int(*pfun)(int,int)
pfun 变量
int(*)(int,int) 类型