2.7 C++ 新增的new和delete运算符
在C语言中,动态分配内存用 malloc() 函数,释放内存用 free() 函数,在C++中,这两个函数仍然可以使用。
示例代码: malloc()和free()函数
using namespace std; //声明默认的命名空间
int main()
{
int *p=(int*)malloc(4); //申请空间
*p=1234;
cout<<"*p="<<*p<<endl;
free(p); //释放空间
return 0;
}
输出结果:
PS D:\linux-share-dir\c_code> .\a.exe
*p=1234
C++除了可以使用malloc()和free()函数外,又新增了两个关键字,new 和 delete。
new 用来动态分配内存,delete 用来释放内存;用 new 和 delete 分配内存更加简单。
示例代码:用 new 和 delete 分配内存
using namespace std; //声明默认的命名空间
int main()
{
int *p=new int; //申请一个int大小的空间
*p=1234;
cout<<"*p="<<*p<<endl;
delete p; //释放空间
return 0;
}
new 操作符会根据后面的数据类型来推断所需空间的大小。
示例代码:连续分配多个字节空间
using namespace std; //声明默认的命名空间
int main()
{
char *p=new char[50]; //申请一个50字节大小的空间
cout<<"请输入一个字符串:";
cin>>p;//从标准输入获取数据
cout<<"p="<<p<<endl;
delete[] p; //释放连续的空间
return 0;
}
输出结果:
PS D:\linux-share-dir\c_code> .\a.exe
请输入一个字符串:hello
p=hello
和malloc()一样,new 也是在堆区分配内存,必须手动释放,否则只能等到程序运行结束由操作系统回收。为了避免内存泄露,通常 new 和 delete、new[] 和 delete[] 操作符应该成对出现,并且不要和C语言中 malloc()、free()一起混用。
在C++中,建议使用 new 和 delete 来管理内存,它们可以使用C++的一些新特性,最明显的是可以自动调用构造函数和析构函数。
2.8 C++函数的默认参数(缺省参数)
在C++中,定义函数时可以给形参指定一个默认的值,这样调用函数时如果没有给这个形参赋值,那么就使用这个默认的值。如果用户指定了参数的值,那么就使用用户指定的值,否则使用参数的默认值。
示例代码:
using namespace std; //声明默认的命名空间
//定义函数的默认参数
void func(int a=666,int b=888){
cout<<"a="<<a<<",b="<<b<<endl;
}
int main(){
func(); //不传参数,使用默认参数
func(123); //传递第一个参数,后面的使用默认参数
func(123,456); //传递实参
return 0;
}
输出结果:
PS D:\linux-share-dir\c_code> .\a.exe
a=666,b=888
a=123,b=888
a=123,b=456
C++规定,默认参数只能放在形参列表的最后,而且一旦为某个形参指定了默认值,那么它后面的所有形参都必须有默认值。实参和形参的传值是从左到右依次匹配的,默认参数的连续性是保证正确传参的前提。
示例:
void func(int a, int b=10, int c=20){ } //正确写法
void func(int a, int b, int c=20){ }//正确写法
void func(int a, int b=10, int c=20, int d){ }//错误写法
void func(int a, int b=10, int c, int d=20){ }//错误写法
除了在函数定义时,可以指定函数的默认参数,也可以在函数声明处指定默认参数。
示例代码: 在函数声明时指定默认参数
using namespace std; //声明默认的命名空间
void func(int a=666,int b=888); //声明函数缺省参数
//定义函数的默认参数
void func(int a,int b){
cout<<"a="<<a<<",b="<<b<<endl;
}
int main(){
func(); //不传参数,使用默认参数
func(123); //传递第一个参数,后面的使用默认参数
func(123,456); //传递实参
return 0;
}
输出结果:
PS D:\linux-share-dir\c_code> .\a.exe
a=666,b=888
a=123,b=888
a=123,b=456
声明是用户可以看到的部分,用户都是信任函数的声明,因此编译器禁止声明和定义同时定义缺省参数值。
比如:下面语法就是错误的
void func(int a=666,int b=888); //声明函数缺省参数
void func(int a=666,int b=888)//定义函数的默认参数
{
cout<<"a="<<a<<",b="<<b<<endl;
}
上面代码中,声明和定义时,都定义了缺省参数,在同一个文件里写是错误的。
在多文件编程时,我们通常的做法是将函数声明放在头文件中,并且一个函数只声明一次,但是多次声明同一函数也是合法的。
C语言有四种作用域,分别是函数原型作用域、局部作用域(函数作用域)、块作用域、文件作用域(全局作用域),C++ 也有这几种作用域。
2.9 C++函数重载详解
函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重载函数。重载函数通常用来命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于程序的可读性有很大的好处。
例如: 希望交换两个变量的值,这两个变量有多种类型,可以是 int、float、char、bool 等,需要通过参数把变量的地址传入函数内部,对于C语言代码,程序员通常需要分别设计出四个不同名的函数,来完成不同的4种类型交换。
示例代码:C语言设计出四个不同名的函数,完成交换功能
void func1(int *a,int *b){…};
void func2(char *a,char *b) {…};
void func3(float *a,float *b) {…};
void func4(bool *a,bool *b) {…};
但在C++中,就很容易实现, C++ 允许多个函数拥有相同的名字,只要它们的参数列表不同就可以,这就是函数的重载(Function Overloading),借助重载,一个函数名可以有多种用途,方便用户调用,用户也无需记住多个函数名字。
示例代码:c++代码
using namespace std; //声明默认的命名空间
//函数声明
void func(int *a,int *b);
void func(char *a,char *b);
void func(float *a,float *b);
void func(bool *a,bool *b);
//交换整型
void func(int *a,int *b){
int tmp;
tmp=*a;
*a=*b;
*b=tmp;
}
//交换字符类型
void func(char *a,char *b){
char tmp;
tmp=*a;
*a=*b;
*b=tmp;
}
//交换浮点数
void func(float *a,float *b){
float tmp;
tmp=*a;
*a=*b;
*b=tmp;
}
//交换bool类型
void func(bool *a,bool *b){
bool tmp;
tmp=*a;
*a=*b;
*b=tmp;
}
int main(){
/*1. 交换整型变量*/
int int_a=100,int_b=200;
cout<<"交换之前:"<<"a="<<int_a<<",b="<<int_b<<endl;
func(&int_a,&int_b);
cout<<"交换之后:"<<"a="<<int_a<<",b="<<int_b<<endl;
/*2. 交换字符类型变量*/
char char_a='A',char_b='B';
cout<<"交换之前:"<<"a="<<char_a<<",b="<<char_b<<endl;
func(&char_a,&char_b);
cout<<"交换之后:"<<"a="<<char_a<<",b="<<char_b<<endl;
/*3. 交换浮点类型变量*/
float float_a=1.123,float_b=2.456;
cout<<"交换之前:"<<"a="<<float_a<<",b="<<float_b<<endl;
func(&float_a,&float_b);
cout<<"交换之后:"<<"a="<<float_a<<",b="<<float_b<<endl;
/*4. 交换字符类型变量*/
bool a=true,b=false;
cout<<"交换之前:"<<"a="<<a<<",b="<<b<<endl;
func(&a,&b);
cout<<"交换之后:"<<"a="<<a<<",b="<<b<<endl;
return 0;
}
输出结果:
PS D:\linux-share-dir\c_code> g++ .\app.cpp
PS D:\linux-share-dir\c_code> .\a.exe
交换之前:a=100,b=200
交换之后:a=200,b=100
交换之前:a=A,b=B
交换之后:a=B,b=A
交换之前:a=1.123,b=2.456
交换之后:a=2.456,b=1.123
交换之前:a=1,b=0
交换之后:a=0,b=1
函数的重载的规则:
(1)、函数名称必须相同。
(2)、参数列表必须不同(个数不同、类型不同、参数排列顺序不同等)。
(3)、函数的返回类型可以相同也可以不相同。
(4)、仅仅返回类型不同不足以成为函数的重载。
C++代码在编译时会根据参数列表对函数进行重命名,当发生函数调用时,编译器会根据传入的实参去逐个匹配,以选择对应的函数,如果匹配失败,编译器就会报错,这叫做重载决议(Overload Resolution)。
函数重载仅仅是语法层面的,本质上它们还是不同的函数,占用不同的内存,入口地址也不一样。