符号常量
符号常量,也称const常量,是用来表示一个常量的标识符。定义const常量的语法
格式为: const <类型> <常量名>=<表达式>;例如:
• const double PI=3.1415926;
• 提示: 在程序中使用符号常量可以提高程序的可读性和可维护性。例如将数值计算
中经常使用的一些参数定义为符号常量,当需要改变参数数值时,只需要更改符号
常量的定义语句就行了。
• 在编程时,符号常量同变量一样,都必须“先定义,后使用”。
例如:
#include<iostream>
using namespace std;
const double PI=3.14; // 可根据需要随时调整PI的精度
int main()
{
double r; //定义表示圆的半径的变量
cout<<"请输入圆的半径:";
cin>>r; //输入圆的半径
cout<<"圆的周长是:"<< 2*PI*r<<endl;
cout<<"圆的面积是:"<<PI*r*r<<endl;
return 0;
}
标准输入输出流
在C语言中,输入输出通过调用scanf()和printf()来实现,而C++中则是使用类
对象cin和cout来实现。
• cin是系统在命名空间std中预先定义好的标准输入流对象,代表标准输入设备—
—键盘。
• 当程序需要从键盘输入时,可以使用提取运算符“>>”从输入流对象cin中提取
从键盘输入的字符或数字,并将其存储到指定变量所在的内存空间。
• cout是系统预先定义好的标准输出流对象,代表标准输出设备——屏幕。
• 当程序需要向屏幕显示输出时,可以使用插入运算符“<<”将字符或数字插入
到输出流对象cout上,就可以将其显示在屏幕上。
• 为了更好地控制输入/输出格式,C++提供了格式控制函数和格式控制符。
控制符是在头文件iomanip中定义的对象,可以将控制符直接插入流中。如
dec、hex、oct、setfill©等。
例如:
//将用户输入的一个整数分别以十进制、八进制和十六进制的格式输出。
#include<iostream>
#include<iomanip>
using namespace std;
int main()
{
int num;
cout<<"请输入一个整数:";
cin>>num;
cout<<"十进制形式:"<<num<<endl;
cout<<"八进制形式:"<<oct<<num<<endl;
cout <<"十六进制形式:"<<hex<<num<<endl;
cout<<dec; // 恢复默认设置
return 0;
}
内联函数
- 当调用一个函数时,系统会将当前函数的运行状态保存起来,然后再去执行
被调用的函数;当被调用的函数执行完毕后,系统会将刚才保存的运行状态
恢复,继续执行函数调用后面的运算。 - 运行环境的保存和恢复、函数跳转都要消耗一定的时间。如果被调用函数实
现的功能比较复杂,其计算时间会远远大于函数调用所额外消耗的时间,此
时函数调用所带来的额外时间开销就可以忽略不计。但是如果被调用函数实
现的功能非常简单并且将被非常频繁调用,在编写程序时就必须要考虑因函
数调用所造成的额外时间开销。 - 为了解决上述问题,一种比较好的方案就是使用内联函数。在编译程序时,
系统会直接将调用内联函数的地方用内联函数中的语句体做等价替换。这样,
在程序运行时就不需要函数调用,从而避免运行环境保存和恢复以及函数跳
转所引起的额外时间开销,提高程序的执行效率。 - 内联函数定义的一般格式如下:
inline <函数类型> <函数名>([<形参表>])
{
函数体
}
在函数定义的<函数类型>前加上inline关键字,即为内联函数的定义。
注意
(1)内联函数只适用于功能简单的小函数。对于函数体中包含循环、switch等复杂结构控制语句的函数及语句比较多的函数,即便该函数被定义为内联函数,编译器也往往会放弃内联方式,将其作为普通函数处理。
(2)必须在内联函数定义处给出inline关键字。如果仅在函数声明时给出inline关键字,而在函数定义时未给出inline关键字,则该函数会被编译器视为普通函数
(3)inline只是一种请求,编译器不一定会允许这种请求,所以一般用内联函数都是一些计算或者输出语句
带默认形参值的函数
- 在调用函数时,需要针对函数中的每一个形参给出对应的实参。C++中也允许
在函数定义或函数声明时给出默认的形参值。在调用函数时,对于有默认值的
形参,如果没有给出相应的实参,则函数会自动使用默认形参值;如果给出相
应的实参,则函数会优先使用传入的实参值。 - 指定默认形参值的位置:默认形参值可以在两个位置指定:如果有函数声明,
则应在函数声明处指定;否则,直接在函数定义中指定。
实例:
#include <iostream>
using namespace std;
void f(char *str="abc"); //默认值在函数声明处指定
int main()
{
f(); // 没有传入实参,此时形参str使用默认值"abc",执行后输出“abc”
f("def");// 传入实参,此时形参str的值为"def",执行后输出“def”
return 0;
}
void f(char *str) //此处不再给出默认值
{
cout<<str<<endl;
}
注意:
- 对于有默认值的形参,如果在调用函数时给出了相应的实参,则会优先使用传入的实参值。如执行“f(“def”);”会输出def。
- 如果有函数声明,则应在函数声明中给出默认形参值,函数定义中不要重复。比如:
void f(char *str = “abc”); // 函数声明部分
void f(char *str = “abc”) // 函数定义部分。错误:默认形参值被重复指定
{ … } - 默认形参值可以是全局常量、全局变量,甚至是可以通过函数调用给出,但不能是局部变量。因为形参默认值或其获取方式需在编译时确定,而局部变量在内存中的位置在编译时无法确定。
- 默认形参值的指定顺序
默认形参值必须严格按照从右至左的顺序进行指定。比如:
void f(int a=1, int b, int c=3, int d=4);
这种指定默认形参值的写法有误。这是由于在第2个参数b未指定默认形
参值的情况下,给出了第1个参数a的默认形参值,不符合从右至左的指
定顺序。
默认形参值的指定顺序示例:
#include <iostream>
using namespace std;
void f(int a, int b=2, int c=3, int d=4) // 带默认形参值的函数定义
{
cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl;
}
int main()
{
f(1); // 输出1 2 3 4
f(5, 10); // 输出5 10 3 4
f(11, 12, 13); // 输出11 12 13 4
f(20, 30, 40, 50); // 输出20 30 40 50
// f(); // 错误
return 0;
}
函数重载
C++允许不同的函数具有相同的函数名,这就是函数重载。
当调用一个函数时,除了要写出函数名,还要根据函数的形参列表传递实参值。对于函数名相同的多个函数,要在调用时能够区分开到底要调用哪个函数,只能
根据传递实参在数量或类型上的不同来进行判断。也就是说,函数名相同的函数形参列表不能完全一样,否则会因无法区分而报错。
例:
最大值函数的重载。
提示:两个max函数形参的数据类型虽然相同,但数量不同,因此,在调用
max函数时,系统会根据传入的实参数量决定调用哪个max函数。
// max.cpp
#include <iostream>
using namespace std;
int max(int x, int y);
int max(int x, int y, int z);
int main()
{
int a = 5, b = 10, c = 15;
cout<<max(a, b)<<endl;
cout<<max(a, b, c)<<endl;
return 0;
}
int max(int x, int y)
{
cout<<"int max(int x, int y)被调用!"<<endl;
return (x>y)?x:y;
}
int max(int x, int y, int z)
{
int c;
cout<<"int max(int x, int y, int z)被调用!"<<endl;
c = (x>y)?x:y;
return (c>z)?c:z;
}
提示:
- 功能相近的函数才有必要重载,互不相关的函数进行重载会降低程序的可读性。
重载的函数必须在形参列表上有所区别。如果仅仅是返回类型不同,不能作为重载函数。比如:
int myabs(int a);
float myabs(int b); // 错误:与“int myabs(int a);”相比只有返
回类型不同,不构成重载 - 避免默认形参所引起的函数二义性。比如:
int max(int a, int b);
int max(int a, int b, int c=0);
从形式上来看,两个max函数的形参数量不同,符合函数重载的条件。但实际
上,两个max函数都可以通过“max(a, b)”的形式进行调用,此时就产生了二义性。
函数重载中const的运用
实例:
void fun1(int & a)
{}
void fun1(int const & a) //底层const
{}
void fun2(int* a)
{}
void fun2(int *const a) //顶层const,修饰指针变量
{} //error,顶层const不能用于函数重载
void fun2(int const* a) //底层const,修饰指针变量指向的数据
{}