C中的命名空间
1)在C语言中只有一个全局作用域;
2)C语言中所有的全局标识符共享同一个作用域;
3)标识符之间可能发生冲突 。
C++中提出了命名空间的概念
1)命名空间将全局作用域分成不同的部分;-->划分作用域
2)不同命名空间中的标识符可以同名而不会发生冲突;-->不同作用域内互不干扰
3)命名空间可以相互嵌套; -->类似C中结构体的嵌套
4)全局作用域也叫默认命名空间;
C++命名空间的定义:namespace name { … }
C++命名空间的使用:
1)使用整个命名空间:using namespace name;
2)使用命名空间中的变量:using name::variable;
3)使用默认命名空间中的变量:::variable;
40默认情况下可以直接使用默 认命名空间中的所有标识符;
C++中namespace,是指标识符的各种可见范围。C++标准程序库中的所有标识符都被定义于一个名为std的namespace中。
使用<iostream>的时候,该头文件没有定义全局命名空间,必须使用namespace std;这样才能正确使用cout。
由于namespace的概念,使用C++标准程序库的任何标识符时,可以有三种选择:
1)、直接指定标识符。例如std::ostream而不是ostream。完整语句如下: std::cout << std::hex << 3.4 << std::endl;
2)、使用using关键字。 using std::cout; using std::endl; using std::cin; 以上程序可以写成 cout << std::hex << 3.4 << endl;
3)、最方便的就是使用using namespace std; 例如: using namespace std;这样命名空间std内定义的所有标识符都有效(曝光)。就好像它们被声明为全局变量一样。那么以上语句可以如下写: cout <<hex << 3.4 << endl;
例子
namespace NameSpaceA
{
int a = 0;
}
namespace NameSpaceB
{
int a = 1;
namespace NameSpaceC
{
struct Teacher
{
char name[10];
int age;
};
}
}
int main()
{
using namespace NameSpaceA;
using NameSpaceB::NameSpaceC::Teacher;
printf("a = %d\n", a);
printf("a = %d\n", NameSpaceB::a);
NameSpaceB::NameSpaceC::Teacher t2
Teacher t1 = {"aaa", 3};
printf("t1.name = %s\n", t1.name);
printf("t1.age = %d\n", t1.age);
system("pause");
return 0;
}
小结:
- 当使用<iostream>的时候,该头文件没有定义全局命名空间,必须使用namespace std;这样才能正确使用cout。若不引入using namespace std ,需要这样做。std::cout。
- c++标准为了和C区别开,也为了正确使用命名空间,规定头文件不使用后缀.h。
- C++命名空间的定义: namespace name { … }
- using namespace NameSpaceA;
- namespce定义可嵌套。
“实用性”增加
C语言中的变量都必须在作用域开始的位置定义!而C++中更强调语言的“实用性”,所有的变量都可以在需要使用时再定义。
#include <iostream>
using namespace std;
int main()
{
int i = 0;
cout<<"aaa"<<endl;
int j = 1;
cout<<j<<endl;
system("pause");
return 0;
}
register关键字增强
1)register关键字 请求编译器让变量a直接放在寄存器里面,速度快
2)在c语言中 register修饰的变量 不能取地址,但是在c++里面做了内容
3) register关键字的变化:
register关键字请求“编译器”将局部变量存储于寄存器中;
C语言中无法取得register变量地址,C++中可以取得register变量的地址;
在C++中依然支持register关键字,C++编译器有自己的优化方式,不使用register也可能做优化;
C++编译器发现程序中需要取register变量的地址时,register对变量的声明变得无效。
register int a = 0;
printf("&a = %x\n", &a);
变量检测增强
在C语言中,重复定义多个同名的全局变量是合法的,但在C++中,不允许定义多个同名的全局变量
C语言中多个同名的全局变量最终会被链接到全局数据区的同一个地址空间上
int g_var;
int g_var = 1;
C++直接拒绝这种二义性的做法。
struct类型加强
C语言中,struct定义一组变量的集合,C编译器不认为它为一种新的类型;
C++中struct是一个新类型的定义声明和class关键字完成的功能一样;
struct Student{
char name[50];
int age;
};
//C 语言中定义及声明变量
struct Student s1 = {"niuxiao", 1};
C++中定义及声明变量
Student s1 = {"niuxiao", 1};
C++ 中所有的变量和函数都必须有类型
C++强调类型,任意的程序元素都必须显示指明类型
//C 语言
int fun();//表示返回值为int,接受任意参数的函数
int g(void);//表示返回值为int的无参函数
//C++
//int fun();与int fun(void);//都表示返回值为int的无参函数
新增的Bool类型关键字
C++中的布尔类型(bool),其取值只有true和false,且理论上bool只占用一个字节
C++编译器 会在赋值时将非0值转换为true,0值转换为false
三目运算符功能增强
C语言中返回变量的值,而C++返回变量本身;
(a<b ? a:b) = 30;
//C 语言中会报错
//C++ 中正常使用
C语言中的三目运算符返回的是变量值,不能作为左值使用;
C++中的三目运算符可直接返回变量本身,因此可以出现在程序的任何地方;
注意:三目运算符可能返回的值中如果有一个是常量值,则不能作为左值使用
(a<b? 1:b) = 30 //erro:有可能返回一个常量值1
C语言怎么支持三目运算符当左值?
当左值的条件:要有内存空间,C++编译器帮助程序猿去了一个地址;
int a,b;
*(a<b? &a:&b)=30;
C /C++中的const
const基础
初步理解const是定义常量,即const 定义变量的值不可更改,只读,结合具体例子分析const用法
const int a; // 表示一个常整数
int const b;
const int *c; //c是一个指向常整形的指针(所指向的内存数据不能被修改,本身值可以修改)
int *const d; // d为常指针,指针变量不能被修改,它所指向的内存空间可以被修改
const int *const e; //e一个指向常整形的常指针,指针和它所指向的内存空间均不能被修改
合理使用const好处:
指针做函数参数,提高代码可读性,减少bug;清楚的分清参数的输入和输出特性;
int setTeacher (const Teacher *p);
//const修改参数时,在利用形参不能修改指针所指向的内存空间
const和#define相同之处
//#define N 10
int main(){
const int a = 1;
const int b = 2;
int array[a+b] = {0};
int i=0;
for(i=0;i<(a+b);i++)
{
printf("array[%d] = %d\n",i,array[i]);
}
getchar();
return 0;
}
C++ 中const修饰的是一个真正的常量,而不是C中变量(只读)。在const修饰的常量编译期间,就已经确定下来
const和#define区别
C++中的const 常量类似与宏定义 const int c =5; 类似:#define c 5
不同地方:const常量是编译器处理的,提供类型检查和作用域检查,宏定义右预处理器处理,单纯的文本替换
//在func1定义a,在func2中能使用
//在func1中定义的b,在func2中不能使用
#include<stdio.h>
void fun1()
{
#define a 10
const int b = 20;
//#undef a # undef
}
void fun2()
{
printf("a = %d\n", a);
//printf("b = %d\n", b);
}
int main()
{
fun1();
fun2();
return 0;
}
小结:
C语言中的const变量是只读常量,有自己的存储空间;
C++中const常量可能分配存储空间,也可能不分配存储空间;当const常量为全局,并且需要在其他文件中使用
当使用&操作符取const常量的地址时,会分配存储空间。
当const int &a =10;const修饰应用时,也会分配存储空间
引用
之前学习的变量名,实质是一段连续存储空间的别名,类似一个‘门牌号’,程序通过变量来申请并命名内存空间,通过变量名使用存储空间;
C++中新增引用概念,引用可以看作一个已定义变量的别名;
//引用语法
Type& name = var;
引用定义时必须进行初始化
int main(){
int a =10;
int &b=a;//引用声明时必须进行初始化
//int &b;//为初始化,erro
printf("%d,%d\n",a,b);
return 0;
}
引用作为函数参数声明时不进行初始化
class Test{
public:
int test1(int &c){
int n= c;
return n;
}
};
int main(){
int a =10;
int &b=a;//引用声明时必须进行初始化
//&b=a;
Test test;
int y = test.test1(a);
printf("%d,%d,%d\n",a,b,y);
return 0;
}
引用在一些场合可以替代指针,且具有更好的可读性和实用性
示意图3
引用实质是C++编译器帮我们取变量在内存中地址
using namespace std;
int main()
{
int a = 10;
int &b = a;
//b是a的别名,请问c++编译器后面做了什么工作?
b = 11;
//cout<<"b--->"<<a<<endl;
printf("a:%d\n", a);
printf("b:%d\n", b);
printf("&a:%d\n", &a);
printf("&b:%d\n", &b); //请思考:对同一内存空间可以取好几个名字吗?
system("pause");
return 0;
}
/*
a:11
b:11
&a:7339572
&b:7339572*/
思考1:对同一内存空间可以取好几个名字吗?---.>可以
思考2:普通引用有自己空间吗? ---》有,引用是一个有地址,引用是常量??
struct Teacer {
int &a;
int &b;
};
int main()
{
int a=10;
int *p = &a;
int &b =a;
printf("a:%d,&a: %d,p: %d,*p: %d,b:%d\n",a,&a,p,*p,b);
printf("sizeof(Teacher) %d\n", sizeof(Teacer));
system("pause");
return 0;
}
/*
a:10,&a: 7339580,p: 7339580,*p: 10,b:10
sizeof(Teacher) 16 */
引用的本质
1)引用在C++中的内部实现是一个常指针,Type& name <==> Type *const name;
2)C++编译器在编译过程中使用常指针作为引用的内部实现,因此引用占用的空间大小与指针相同
3)从使用角度,引用会让人误以为只是一个别名,没有自己的存储空间;
指针引用
引用相当于取变量地址,功能类似指针变量
//指针的引用而已
int getTe2(Teacher* &myp)
{
//给myp赋值,相当于给main函数中的PT赋值
myp = (Teacher *)malloc(sizeof(Teacher));
myp->age = 34;
return 0;
}
int main()
{
//普通引用
int a=10;
int &b =a;
printf("b:%d\n",b);
Teacher *pT = NULL;
//C++的指针引用
//引用的本质,间接赋值后2个条件,让C++编译器帮我们程序员做了。
getTe2(pT);
printf("age:%d \n", pT->age);
FreeTeacher(pT);
system("pause");
return 0;
}
常引用
const引用让变量拥有只读属性
//普通引用
int a = 10;
int &b = a;
//常量引用 :让变量引用只读属性
const int &c = a;
inline 内敛函数
C++中推荐使用内联函数替代宏代码片段,且内联函数声明时inline关键字必须和函数定义结合在一起使用,否则编译器会忽略内联请求。
#define MYFUNC(a, b) ((a) < (b) ? (a) : (b))
inline int myfunc(int a, int b)
{
return a < b ? a : b;
}
int main(){
int a = 1;
int b = 3;
//int c = myfunc(++a, b); //头疼系统 a=2,b=3,c=2 -》myfun(2,3)
int c = MYFUNC(++a, b); //宏替换并展开 ((++a) < (b) ? (++a) : (b))
}
小结
1)内联函数在编译时直接将函数体插入函数调用的地方;
2)inline只是一种请求,编译器不一定允许这种请求;
3)内联函数省去了普通函数调用时压栈,跳转和返回的开销;
函数重载
C++允许功能相近的函数在相同的作用域内以相同函数名声明,从而形成重载。方便使用,便于记忆;
函数重载指用同一个函数名定义不同的函数,即当函数名和不同参数搭配时函数的含义不同;
判断函数重载的3个标准:1)参数个数不同;2)参数类型不同;3)参数顺序不同;
//形参类型不同
int add(int x,int y);
float add(float x,float y);
//形参个数不同
int add(int x, int y,int z);
注意事项:
- 重载函数形参必须不同:个数不同或类型不同;
- 编译程序将根据实参和形参的类型及个数的最佳匹配来选择调用哪一个函数;
- 编译器不以形参名、返回值来区分;
不要将不同功能的函数声明为重载函数,以免出现调用结果的误解、混淆,如下错误形式;
//错误示范
int add(int x,int y){return x+y};
float add(float x,float y){return x-y};
重载函数应用举例
编写两个名为sumOfSquare的重载函数,分别求两整数的平方及两实数的平方和;
/*C++程序设计_清华陈莉:3_15_sumOfSquare.cpp*/
#include<iostream>
using namespace std;
int sumOfSquare(int a,int b){
return a*a+b*b;
}
double sumOfSquare(double a,double b){
return a*a+b*b;
}
int main(){
int m,n;
cout<<"Enter two intger:";
cin>>m>>n;
cout<<"Their sum of square:"<<sumOfSquare(m,n)<<endl;
double x,y;
cout<<"Enter two real number:";
cin>>x>>y;
cout<<"Their sum of square:"<<sumOfSquare(x,y)<<endl;
return 0;
}
Enter two intger:1 5
Their sum of square:26
Enter two real number:1.11 4.11
Their sum of square:18.1242