什么是C++?
概念 :C++是基于C语言而产生的,它既可以进行C语 言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行面向对象的程序设计。
命名空间
概念:在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作 用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字 污染,namespace关键字的出现就是针对这种问题的。
在命名空间时,我们需要使用到namespace关键字,在namespace后加空间名字,将其内容用{}括起即可,{}中即为命名空间的成员。
代码示例
namespace N1//命名空间的成员可以是变量、函数
{
int a = 10;
int b = 10;
int Add(int left, int right)
{
return left + right;
}
}
namespace N1
{
int c = 20;
int d = 20;
int Mul(int left, int right)
{
return left * right;
}
}
namespace N2
{
int a = 30;
int b = 30;
int Sub(int left, int right)
{
return left - right;
}
namespace N3
{
int a = 40;
int b = 40;
int Mul(int left, int right)
{
return left * right;
}
}
}
使用命名空间成员的三种方式
- 方法一:命名空间名 + “::” + 成员。“::”叫作用域限定符
代码示例
printf("%d\n", N1::a);
printf("%d\n", N2::a);
printf("%d\n", N1::Add(10, 10));
- 方法二:using + 命名空间名 + 成员
适用场景:该成员使用的次数较多,且不会产生冲突
代码示例
using N2::N3::a;
printf("%d\n", a);
- 方法三:using namespace + 命名空间名
适用场景:该命名空间使用次数特别多,命名空间中的成员可以直接在当前文件中直接使用,但容易产生冲突。
代码示例
using namespace N2::N3;
printf("%d\n", b);
printf("%d\n", Mul(40, 20));
输入输出流
在C++中输入输出不再使用“ scanf ”和“ printf ”,而是有自己的标准输入输出流“ cin ”和“ cout ”,它们不再是函数,而是类对象。“ cin ”和“ cout ”可以接受任何类型的变量。
注意: 当使用标准输入输出流时,必须包含头文件 "iostream"和“using namespace std;”,且不需增加数据格式控制,比如:整形–%d,字符–%c。
代码示例
#include<iostream>
using namespace std;
#if 0
int main()
{
char name[20];
cin >> name;
cout << "姓名是: "<< name << endl;
return 0;
}
#endif
int main()
{
int a;
double b;
char c;
cin >> a;
cin >> b >> c;
cout << a << endl;
cout << b << " " << c << endl;
system("pause");
return 0;
}
缺省参数
我们的日常生活中,女神和男神的身边常常有备胎的陪伴。在C++的世界中也存在备胎。C++的备胎就是缺省参数。在声明或定义函数时,给函数的参数一个默认值,在调用该函数时,若给定了实参,则打印实参;若没有给定实参,则打印给定的默认值。这里的默认值就相当于该参数的“备胎”。
代码示例
int Add(int left = 10, int right = 20)
{
return left + right;
}
int main()
{
int a;
int b;
cin >> a >> b;
cout << Add() << endl << Add(a, b) << endl;
system("pause");
return 0;
}
运行结果
1 2
30
3
请按任意键继续. . .
缺省参数的分类
缺省函数可以分为两类,全缺省参数和半缺省参数。顾名思义,全缺省参数就是函数内的所有形参都给定了默认值,半缺省参数就是给定其中若干个形参的默认值。
注意
- 在半缺省参数中,必须按照从右到左的次序给定形参的默认值,不能隔空,因为默认形参必须在形参列表的结尾。
- 缺省值必须是常量或者全局变量
- C语言不支持(编译器不支持)
- 缺省参数不能在函数声明和定义中同时出现。如果声明与定义位置同时出现,恰巧两个位置提供的值不同,那编译器就无法确定到底该用那 个缺省值
代码示例
全缺省参数
void TestFunc(int a = 10, int b = 20, int c = 30)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
}
半缺省参数
//全缺省参数
void TestFunc1(int a = 10, int b = 20, int c = 30)
{
cout << "a = " << a << " " << "b = " << b << " "<< "c = " << c << endl;
}
//半缺省参数
void TestFunc2(int a, int b = 10, int c = 40)
{
cout << "a = " << a << " " << "b = " << b << " " << "c = " << c << endl;
}
函数重载
概念:函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或类型或顺序)必须不同,常用来处理实现功能类似数据类型不同的问题。
代码示例
int Add(int a, int b)
{
return a + b;
}
double Add(double a, double b)
{
return a + b;
}
int main()
{
printf("%d\n",Add(10, 20));
printf("%lf\n",Add(1.1, 2.2));
system("pause");
return 0;
}
如果俩个函数只是因为返回值不同,则不能构成函数重载。
那么函数重载是在那个过程实现的呢?我们知道,代码跑起来要经过预处理、编译、汇编、链接四个阶段,函数重载就是在编译阶段完成的。在编译阶段。编译器会对函数的实参进行推演,找到与之匹配的函数则进行调用,如果没有找到类型匹配的函数,则编译器会进行隐式类型转换,转换完成有可调用的函数则编译成功,转换完成没有可调用的函数则编译失败。
代码示例
printf("%lf\n", Add('1', '2'));//没有提供char类型的加法函数,编译器会进行隐式类型转换,将char类型转换成int类型
printf("%d\n", Add(1, (int)2.2));//实参一个是int类型,一个是double类型,编译器不知道是该将int转换成double还是将double转换成int,会出现报错,这时,需要自己给出转换方式,此处是将double转换成int
简单说明一下这四个过程:
那么在C语言中为什么没有函数重载?
我们先来看看下面这段代码可以成功编译吗?
int Add(int a, int b);
double Add(double a, double b);
函数在链接的时候找的不是函数名,而是编译后函数的别名。C语言环境中,这段代码在编译阶段可以通过,但在链接阶段就会报错,C语言中的名字修饰规则就是在函数名前加“_” 得到修饰后的名称,只要调用的是同名函数,不管形参列表是否相同,函数别名都是一样的,所以在调用时,编译器会显示重定义错误。而在C++环境中,名字修饰规则一般情况是问号+函数名+@@+YA+参数类型的符号+@Z。
代码示例
//(?Add@@YANNN@Z)
int Add(int left, int right);
//(?Add@@YAHHH@Z)
double Add(double a, double b);
//(?Add@@YAHNH@Z)
double Add(int a, double b);
//(?Add@@YANHN@Z)
int Add(double left, int right);
由此可见,在C++环境下,函数编译后的别名因为参数列表的类型、顺序、或个数的不同而不同,所以在链接时,对编译器来说,这些同名函数是不一样的。
那么,C++中为什么会有函数重载呢,它存在的意义是什么?
在C语言中,是没有函数重载的,我们要实现不同参数列表的Add函数,就要给Add函数取不同的名字,就需要为实现同一个功能的函数取很多个名字,这样做很不友好。使用同名函数减少了函数名的数量,降低了名字空间的污染,当使用的函数名和全局变量越来越多的时候,就不再容易区分彼此之间的问题,在一定程度上给程序员造成编写上的麻烦,函数重载就提高了代码的可读性。在C++中,类的构造函数跟类名相同,也就是说:构造函数都同名。如果没有函数重载机制,要想实例化不同的对象,是很麻烦的。
注意:如果只是函数的返回值不同,那不算函数重载。
代码示例
int Add(int a, int b)
{
return a + b;
}
double Add(int a, int b)
{
return a + b;
}
int main()
{
Add(1, 2);
return 0;
}
运行结果
当我们没有给定返回值时,编译器并不知道要调用int类型还是double类型时就会报错。并不能形成函数重载。