1、c++输入输出
#include<iostream>
// std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中
using namespace std;
int main()
{
cout<<"Hello world!!!"<<endl;
return 0;
}
//流插入运算符 << 在一个语句中可以多次使用,如上面实例中所示,endl 用于在行末添加一个换行符。
说明:
- 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件以及按命名空间使用方法使用std。
#include <iostream>
using namespace std;
int main( )
{
char name[50];
cout << "请输入您的名称: ";
cin >> name;
cout << "您的名称是: " << name << endl;
}
- cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含< iostream >头文件中。
- <<是流插入运算符,>>是流提取运算符。
- 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。C++的输入输出可以自动识别变量类型。
注意:
早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应头文件即可,后来将其实现在std命名空间下,为了和C头文件区分,也为了正确使用命名空间, 规定C++头文件不带.h;旧编译器(vc 6.0)中还支持格式,后续编译器已不支持,因此推荐使用<iostream>+std的方式。
std命名空间的使用惯例:
std是C++标准库的命名空间,如何展开std使用更合理呢?
- 在日常练习中,建议直接using namespace std即可,这样就很方便。
- using namespace std展开,标准库就全部暴露出来了,如果我们定义跟库重名的类型/对象/函数,就存在冲突问题。该问题在日常练习中很少出现,但是项目开发中代码较多、规模大,就很容易出现。所以建议在项目开发中使用,像std::cout这样使用时指定命名空间 + using std::cout展开常用的库对象/类型等方式。
2、缺省参数
2.1、缺少参数概念
缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。
- 通俗点讲,就是在定义函数的时候可以给形参赋一个初始化的值,这个值就叫做缺省值,缺省值可以有一个,也可以有多个
void Func(int a = 0)
{
cout<<a<<endl;
}
int main()
{
Func(); // 没有传参时,使用参数的默认值
Func(10); // 传参时,使用指定的实参
return 0;
}
2.2、缺省参数分类
- 全缺省参数
void Func(int a = 10, int b = 20, int c = 30)
{
cout<<"a = "<<a<<endl;
cout<<"b = "<<b<<endl;
cout<<"c = "<<c<<endl;
}
- 半缺省参数
void Func(int a, int b = 10, int c = 20)
{
cout<<"a = "<<a<<endl;
cout<<"b = "<<b<<endl;
cout<<"c = "<<c<<endl;
}
注意:
1.半缺省参数必须从右往左依次来给出,不能间隔着给
2.缺省参数不能在函数声明和定义中同时出现
//a.h
void Func(int a = 10);
// a.cpp
void Func(int a = 20)
{}
// 注意:如果生命与定义位置同时出现,恰巧两个位置提供的值不同,那编译器就无法确定到底该
用那个缺省值。
- 一般我们会选择定义在声明处,因为声明处的头文件
.cpp
也可以包含其他文件。若是将这些缺省参数放在了定义处,其他文件就没办法使用到了
3.缺省值必须是常量或者全局变量
- 这一点很好理解,你给出的缺省值必须是一个固定的值,而不是一个可修改的变量,否则这个缺省值将毫无意义;对于缺省值一般我们不会使用全局变量,因为全局变量会存在线程安全的问题,日常写代码也是不推荐使用全局变量
4.C语言不支持(编译器不支持)
2.3、缺省参数使用实例
void Func(int a = 10, int b = 20, int c = 30){
cout<<"a = "<<a<<endl;
cout<<"b = "<<b<<endl;
cout<<"c = "<<c<<endl;
}
int main(void){
Func(1,2,3);
Func(1,2);
Func(1);
Func();
}
结果
可以看出,刚才我都是执行【从右往左依次连续给出缺省值】的,但若是我像下面这样传递参数的话,虽然是规则对的,但语法是错误的
func(, 1);
func(, 1, 2);
func(, ,1);
2.4、半缺省参数
并不是所有的形参都有缺省值,可以是一个也可以是多个。
其常见错误示范:
- 没有从右往左进行缺省
若是想要给出第2个缺省值,那么第3个就必须给出;若是想要给出第1个缺省值,那么那么第2个和第3个就必须给出
void func(int a = 10, int b = 20, int c)
void func(int a = 10, int b, int c)
void func(int a, int b = 20, int c)
- 没有连续地给出缺省值(同上,必须要满足从右往左和连续)
//正确写法
void func(int a, int b = 20, int c = 30) //✔ 后两个缺省
void func(int a, int b, int c = 30) //✔ 最后一个缺省
注意:对应实参和形参至少要存在一位,不然会出现随机值
举例:
void func(int a, int b = 20, int c = 30)
func(1, 2, 3); //a = 1 b = 2 c = 3
func(1, 2); //a = 1 b = 2 c = 30
func(1); //a = 1 b = 20 c = 30
func(); //a = ? b = 20 c = 30
3、函数重载
自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重 载了。
比如:以前有一个笑话,国有两个体育项目大家根本不用看,也不用担心。一个是乒乓球,一个 是男足。前者是“谁也赢不了!”,后者是“谁也赢不了!”
3.1、函数重载概念
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这 些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型 不同的问题。
实例1:
#include <iostream>
using namespace std;
class printData
{
public:
void print(int i) {
cout << "整数为: " << i << endl;
}
void print(double f) {
cout << "浮点数为: " << f << endl;
}
void print(char c[]) {
cout << "字符串为: " << c << endl;
}
};
int main(void)
{
printData pd;
// 输出整数
pd.print(5);
// 输出浮点数
pd.print(500.263);
// 输出字符串
char c[] = "Hello C++";
pd.print(c);
return 0;
}
结果:
实列2:
#include<iostream>
using namespace std;
// 1、参数类型不同
int Add(int left, int right)
{
cout << "int Add(int left, int right)" << endl;
return left + right;
}
double Add(double left, double right)
{
cout << "double Add(double left, double right)" << endl;
return left + right;
}
// 2、参数个数不同
void f()
{
cout << "f()" << endl;
}
void f(int a)
{
cout << "f(int a)" << endl;
}
// 3、参数类型顺序不同
void f(int a, char b)
{
cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
cout << "f(char b, int a)" << endl;
}
int main()
{
Add(10, 20);
Add(10.1, 20.2);
f();
f(10);
f(10, 'a');
f('a', 10);
return 0;
}
3.2、(深入理解)c++支持函数重载的原理--名字修饰(name Mangling)
为什么C++支持函数重载,而C语言不支持函数重载呢?
在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接。
进一步理解就是
回顾(编译和链接):
由于Windows下vs的修饰规则过于复杂,而Linux下g++的修饰规则简单易懂,下面我们使 用了g++演示了这个修饰后的名字。
- 实际项目通常是由多个头文件和多个源文件构成,而通过C语言阶段学习的编译链接,我们可以知道,【当前a.cpp中调用了b.cpp中定义的Add函数时】,编译后链接前,a.o的目标文件中没有Add的函数地址,因为Add是在b.cpp中定义的,所以Add的地址在b.o中。那么怎么办呢?
- 所以链接阶段就是专门处理这种问题,链接器看到a.o调用Add,但是没有Add的地址,就 会到b.o的符号表中找Add的地址,然后链接到一起。
- 那么链接时,面对Add函数,链接接器会使用哪个名字去找呢?这里每个编译器都有自己的函数名修饰规则。
采用C语言编译器编译后的结果:
结论:在linux下,采用gcc编译完成后,函数名字的修饰没有发生改变。
采用c++编译器编译后的结果:
结论:在linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参 数类型信息添加到修改后的名字中。
通过上面我们可以看出gcc的函数修饰后名字不变。而g++的函数修饰后变成【_Z+函数长度 +函数名+类型首字母】。
总结:
- 通过这里就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。
- 如果两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时编译器没办法区分。
*扩展学习--C/C++函数调用约定和名字修饰规则(c/c++的调用约定)