c++函数与预处理 string
1.内置函数
#include<iostream>
using namespace std;
//1.内置函数的价值:主要作用地为了提高我们程序的执行效率。
//2.内置函数如何定义:只需要在传统函数定义的基础上,在返回类型的前面加inline关键字,此时该函数就变成了内置函数
//或者叫内联函数。--- 意味着程序在对inline修饰的函数在编译时会做特殊的处理
inline void test()
{
cout<<"test inner function";
}
int main()
{
test();//3.内联函数的调用和传统函数时一样,程序在对其做编程时,会将test()调用语句替换成cout<<"test inner function";
//替换后,在执行程序时 就省掉了保护现场和恢复现场的操作,从而提高了程序的效率。
//4.什么场景适合将函数定义为内置函数:1.该函数在程序中需要被频繁的调用,2,该函数体中的语句比较短小(6条语句以下)
return 0;
}
函数重载
#include<iostream>
using namespace std;
//1.什么是函数重载 就是在同一个作用域,定义多个同名函数,需要确保这些函数的参数个数不一样或参数类型不一样,这样的一组函数叫函数重载
int add(int a, int b) //函数重载成功的条件:要么它们的形参个数不一样,要么形参类型不一样,要么个数和类型都不一样
{
cout<<"两个int相加"<<endl;
return a+b;
}
double add(double a, double b)
{
cout<<"两个double相加"<<endl;
return a+b;
}
int add(int a, int b,int c)
{
cout<<"三个int相加"<<endl;
return a+b+c;
}
//void test(int a ,float b) void test(float a,int b) 这个叫顺序不一样
int main()
{
add(3,5);//在调用重载的某个函数时,它是如何来匹配目标函数,根据用户在调用时 所传递的实参个数和类型来匹配要调用的目标函数
add(1,2,3);
add(2.1,3.4);
return 0;
}
void fun(int a)
{
cout<<"int"<<endl;
}
void fun(int *a)
{
cout<<"int*"<<endl;
}
int main()
{
// add(3,5);//在调用重载的某个函数时,它是如何来匹配目标函数,根据用户在调用时 所传递的实参个数和类型来匹配要调用的目标函数
// add(1,2,3);
// add(2.1,3.4);
//fun(NULL);//在C++中,NULL对函数重载带来了调整,为了解决这个问题,C++提供一个新的关键字来代替NULL
fun(nullptr);//在C++中提供了空指针的关键字nullptr来表示空指针,在C++中不推荐大家用NULL。
return 0;
}
void test(const int* a) //这两个是可以重载成功的
{
cout<<"const int *";
}
void test(int* a)
{
cout<<"int *";
}
int main()
{
int k=10;
test(&k );
return 0;
}
函数模板
#include<iostream>
using namespace std;
//
//int add(int a, int b) //下边这三个函数,虽然能够重载成功,但是发现它们的代码逻辑一样,唯独数据类型不一样,这也是代码的重复
//{
//
// return a+b;
//}
//
//float add(float a,float b)
//{
// return a+b;
//}
//
//double add(double a, double b)
//{
// return a+b;
//}
//函数模板致力于构建一个通用的函数,用一些虚拟的符号来代指任意类型,从而让改函数更通用
//虚拟类型T 具体是啥类型,取决于调用改模版函数时用户的指定。
//<>里主要存放的是模板的形参列表,每个模板形参都有两部分组成:typename +虚拟符号,存在多个形参时用逗号去隔开
//虚拟类型的符号一般建议大写,为了和传统的具体类型做区分。
//修饰虚拟符号 可以用typename关键字来修饰,也可以用class来修饰。template<class T>
template<typename T> //这个就叫函数模板(代表多个函数逻辑一样,唯独类型不一样的场景)。减少代码冗余
T add(T a,T b) //一个函数模版只能代替参数个数相同的一群功能相似的函数
{
return a+b;
}
int main()
{
cout<< add(1,2);//调用函数模版的函数就像调用普通函数一样去调用。
cout<<add(2.3,3.3);//模板函数的调用原理:1.当调用函数模板时,它会根据实参值推断出实参类型然后将该类型传递给虚拟符号
cout<<add(1.0f,3.3f); // .在函数中经虚拟符号出现的地方用具体类型进行替换,然后就生成了一个真正意义的函数
//2.再发起对该函数进行调用。
return 0;
}
#include<iostream>
using namespace std;
//函数模板也支持重载,重载时主要看形参个数,形参类型不需要看 因为虚拟符号可以代指任意类型。
//template<typename T>
//T add(T a,T b)
//{
//
// return a+b;
//}
//虚拟形参列表中可以定义多个虚拟符号,虚拟形参之间用逗号去隔开
//template<typename T,typename K>
//void test(T a,K b)
//{
//
// cout<<a*b;
//
//}
//.如果在一个函数模板中你声明了多个虚拟符号,虚拟符号的名字不能重复。
template<typename T,typename K> //在定义函数模板时,你声明的虚拟类型符号,只能在它紧跟的函数内使用,离开这个函数不能再使用这个虚拟符号
void test(T a,K b)
{
auto ret= a*b;
cout<<ret;
}
//void add(K a)
//{
//
//}
int main()
{
//调用函数模板一般有两种方式:1.类型推断 2,显式指定,通过调用函数模板时在<>内来明确指定类型名称,给虚拟形参T
// cout<< add(1,2); //根据实参值来推断实参类型 将推断出来的类型传递虚拟形参T
// add<int>(1,1);
//
// cout<<add(2.3,3.3);
// cout<<add(1.0f,3.3f);
test<int,double>(2,3.3);
return 0;
}
默认形参
#include<iostream>
using namespace std;
/*
int clifd =accept(serid,NULL,NULL); )
*/
void test(int a) //a就叫必须形参,用户在调用该函数时,必须给该形参提供对应的实参值,否则就会造成调用失败。
{
}
//name形参就叫必须形参,country就叫默认形参,用户如果给第二个形参提供了值 就按照提供值参与运算,不提供按照默认值参与运算
//一个函数中用户可以根据需要定义一个或多个默认形参,一个函数中可以既有默认形参 也可以有普通形参
//如果一个函数中既有默认形参 又有普通形参,需要将默认形参定义在普通形参的后边。
void mytest(string name,string country="中国") //给形参变量提供了一个默认值的形参叫默认形参
{
cout<<name<<country;
}
////使用的时候,要注意默认形参给函数重载带来的影响。
//void test1(int a=1,int c=2)
//{
//
//
//}
//void test1(){}
int main()
{
test(10);
mytest("ljs","英国");
mytest("yangyang");//函数中定义了默认形参,意味调用改函数时,实参对应的默认形参可以提供 也可以不提供,不提供 按默认值处理
return 0;
}
#include<iostream>
using namespace std;
//带默认形参的函数在做函数原型声明和定义时,只能二选一,定义时指定了默认形参 则声明不能再次指定,如果声明指定了 则定义不需要再次指定,推荐后者。
void mytest(int a,int b=0);
void mytest(int a,int b)
{
}
int main()
{
mytest(100);
return 0;
}
引用
#include<iostream>
using namespace std;
int main()
{
int k=100;
//引用类型需要和你绑定的变量类型要一致。
// &在这里叫引用符号 如果&符号前存在数据类型名称 就叫引用符号,如果说&符号前没有数据类型名称 叫取地址符号。
int &mykk=k; //就是给我们的变量K起了一个新的别名叫mykk;
mykk=mykk+10;//通过引用名进行操作 会影响到该别名绑定变量空间中的值,它也是双向的。
cout<<k<<endl;
cout<<&k<<":"<<&mykk;//0x7811ff634:0x7811ff634
// int y=3;
// int &myy;错误的 ---定义引用名的同时必须要对其初始化,不可以先定义后初始化。
int a,b;
int *pt;
pt=&a;//指针是可以改变绑定的变量地址
pt=&b;
// int x=3;
// int &mykk=x; //是错的,在同一个作用域下,引用名一旦绑定到某个变量上,就不可以将该名在绑定到其他变量上。人家比较专一
//引用传参比指针传参要安全。
//注意:引用是给变量绑定一个别名,不可以对常量构建一个左值引用。
return 0;
}
#include<iostream>
using namespace std;
/*
指针传参与引用传参的区别
1)引用传参比指针传参更安全
2)指针可以赋值为NULL,引用不可以。
3)指针可以改变执行,引用一旦被绑定 在同一个作用域下不可以再次绑定到其他变量身上。
4)它们对++的操作含义不一样,指针++是改变指针本身,引用变量++是改变绑定变量空间中的值
5)对sizeof的含义也不一样,对指针加sizeof是代表指针本身所占空间的大小,对引用变量加sizeof代表绑定变量所占空间的大小。
*/
//引用传参不是万能的,不可以完全取代指针传参 比如传递数组,对指针变量本身进行操作来改变指向
//引用类型做函数的形参
void test(int &mykk)//用引用做形参,传参也是双向的,函数内对引用别名的操作是会影响到实参的。
{
mykk=mykk+10;//在函数中操作别名mykk就相当于操作的是a变量
}
int main()
{
int a=100;
cout<<"before:"<<a<<endl;
test(a);
cout<<"after:"<<a<<endl;
return 0;
}
#include<iostream>
using namespace std;
//1.引用也可以做函数的返回类型
//2.不可以在引用类型的函数中 返回一个非静态变量的引用。
int &mytest()
{
static int a=100;
return a;
}
int main()
{
// int a=10;
// int &myaa=a;
//
// cout<<myaa;
// myaa=myaa+1;
//
// int b=11;
// const int &mybb=b; //常引用 目的来保护我们的数据安全,也就是说通过新建的入口可以对绑定变量的空间进行读取 不可以修改。
// cout<<mybb;
// mybb=33;是错的
int &pp=mytest();
cout<<pp;
return 0;
}