函数重载
说说什么是函数重载
函数重载指的是在同一个作用域中,声明了具有相同函数名的函数,它们的参数列表不同,也就是说参数类型不同,参数个数不同,参数顺序不同,返回值同不同都可以。
写一个函数重载的例子:
代码语言:javascript复制/*函数重载*/
int add(int x, int y)
{
cout << "int add(int x, int y)" << endl;
return x y;
}
double add(double x, double y)
{
cout << "double add(double x, double y)" << endl;
return x y;
}
int main()
{
int ret1 = add(1, 2); //3
double ret2 = add(5.5, 4.3);//9.8
cout << ret1 << " " << ret2 << endl;
return 0;
}
为什么C语言不支持函数重载?
因为在链接阶段生成符号表的时候,C语言对函数取名的时候,只会拿函数名进行取名,如果有函数重载的话,没办法区分函数的不同。而C 在取名的时候,是将函数名和参数类型的首字符结合起来对函数的取名,这样就可以区分函数的不同了。
拓展:说说函数重载、函数重写、函数重定义区分:
在作用域中:函数重载在需要在同一个作用域中。函数重定义和函数重写的两个函数必须一个在父类中,一个在子类中,而且函数重写必须是虚函数。
函数重载和函数重定义需要的是函数名相同,参数列表不同,函数重写需要函数名相同、参数列表相同和返回值相同(例外情况是协变和析构函数的重写。协变是返回值可以不同,但是返回值必须是父子关系类的指针或引用。析构函数的重写是函数名不相同)。
引用
说说什么是引用
引用就是给一个变量取别名,跟被引用的变量共用一块地址空间。比如
代码语言:javascript复制int a = 10;
int& ra = a;
在定义的时候必须进行初始化,而且初始化后不能改变引用对象。
说一说引用和指针的区别
①引用在定义时必须初始化,而指针不需要。②引用不能初始化为空引用,而指针可以初始化为空指针。③引用初始化后不能改变指向对象,而指针可以改变指向。④引用没有开辟内存,是与被引用的变量共用内存地址,而指针是开辟了新的空间,用于存放被指向的变量的地址⑤在使用sizeof的时候,引用的结果是引用类型大小,指针的结果是地址空间所占的字节个数。比如有一个double类型的变量b,其引用为rb和指针为pb,那么在sizeof后,得出的结果是8和4.其中,8是double类型的大小,而4是32位平台下,指针的大小。
代码语言:javascript复制 double b = 6.6;
double& rb = b;
double* pb = &b;
cout << sizeof(rb) << endl;//8
cout << sizeof(pb) << endl;//4
⑥引用在自加的时候,是引用的那个实体加一,而指针自加是向后偏移一个类型大小。比如当rb 1,那么是b从6.6变成7.6,而pb 1,是地址往后偏移了4位。
代码语言:javascript复制 cout << rb 1 << endl;//7.6
cout << pb<<"->" << pb 1 << endl;//0055FA6C->0055FA74--每次编译运行都会变
说一说引用的场景,有什么好处
引用一般使用在参数和返回值上面。可以通过引用减少拷贝,提高程序的效率。而作为返回值的话,引用的对象必须不能随函数的销毁而销毁。
关键字
static关键字
说一说static的作用:
static用于修饰局部变量、全局变量和函数。
被修饰的局部变量变成静态局部变量,其作用域不变,但是改变了生命周期,会跟随程序的结束而销毁。
被修饰的全局变量会变成静态全局变量,其作用域改变,不再具有外部链接属性,其它源文件不能使用extern来声明外部符号从而引用这个变量。
被修饰的函数会变成静态函数,其作用域改变,不再具有外部链接属性,其它源文件不能通过extern来声明从而引用这个函数。
在类中,成员变量被修饰后,是属于所有类的,所有类的对象都可以调用它,而且是不需要this指针去引用。
inline关键字
说一说inline关键字
被inline修饰的函数会变成内联函数,在编译的时候,编译器会将内联函数进行展开,不好有函数栈帧的开销。在短小而且频繁调用非递归的函数可以使用内联函数。
说一说宏的优缺点,有什么解决办法
宏的优点是增强代码的复用性,比如用宏来定义一个常量,那么在后续的代码中我或许需要多次用到这个常量。还有就是可以提高性能。比如需要实习一些简单的加减功能的函数,可以使用宏来定义,就避免了函数的栈帧开销,提高性能。
缺点是不方便调式,因为在编译期间进行了替换。代码的可读性比较差,宏展开后代码可能会变得复杂,冗余。没有类型安全的检查,在宏中不会对参数类型进行检查。
写一个宏替换的例子
代码语言:javascript复制#define add(x,y) x y
int main()
{
int a = 1, b = 2;
cout << add(a, b) << endl;
return 0;
}
解决办法是使用内联函数和常量定义,比如const、enum来替换。
const关键字
说一说const关键字
const除了上述,可以使用const来替换宏定义,因为const常量定义是可以进行类型检查、并且具有作用域。
const还能用来修饰局部变量,修饰常量字符串,修饰指针和修饰函数的参数和返回值。
说一说修饰指针的情况
const修饰指针,分有常量指针和指针常量。
常量指针说的是指针的指向是一个常量,不可以通过指针去修改这个常量的值,但是指针可以改变指向。
指针常量说得是它是一个常量,它不可以改变指向,但是可以通过指针修改指向的内容。
代码语言:javascript复制 const int* a;//常量指针,指针a指向的内容不可以通过指针去改变指向的内容,但是可以改变指向
int const* a;//常量指针
int* const a;//指针常量,可以通过指向a去修改内容,但是不可以改变指向
const char* a = "abc";//字符串常量,不可以修改内容和指向
sizeof关键字
sizeof关键字是一个运算符,用来计算数据类型大小,会包含'